DervFlow delivers production-ready option pricers, risk analytics, portfolio construction utilities, time-series diagnostics, and yield-curve analytics backed by rigorously tested numerical kernels.
Caution
Active development. APIs may evolve before a 1.0 release.
- Options pricing – Black-Scholes-Merton analytics, implied volatility solvers, binomial trees, Longstaff–Schwartz Monte Carlo, and exotic payoffs (Asian, barrier, lookback, digital) exposed through ergonomic Python classes.
- Risk analytics – Portfolio Greeks aggregation, historical/parametric/Monte Carlo VaR and CVaR, drawdown analytics, and performance ratios.
- Portfolio construction – Mean-variance optimisation with constraints, efficient frontiers, risk parity allocation, and Black–Litterman blending of market and investor views.
- Yield curves – Bootstrapping from bonds or swaps, Nelson–Siegel(-Svensson) parametrisations, zero/forward/discount curve queries, and bond analytics (duration, convexity, DV01).
- Time series – Return transformations, rolling and EW statistics, autocorrelation diagnostics, hypothesis tests, and GARCH-family volatility models.
- Monte Carlo – High-throughput stochastic process simulators (GBM, Ornstein–Uhlenbeck, CIR, Vasicek) with optional parallel path generation.
- Numerical kernels – Deterministic integrators, root-finders, optimisers, quasi-random generators, and dense linear-algebra helpers implemented in Rust for safety and speed.
The package exposes the compiled extension as dervflow.
from dervflow import BlackScholesModel, MonteCarloOptionPricer, RiskMetrics
import numpy as np
# Analytical Black–Scholes pricing with Greeks
bs = BlackScholesModel()
call_price = bs.price(
spot=100.0,
strike=100.0,
rate=0.05,
dividend=0.02,
volatility=0.20,
time=1.0,
option_type="call",
)
call_greeks = bs.greeks(100.0, 100.0, 0.05, 0.02, 0.20, 1.0, "call")
print(f"Call price: {call_price:.2f}")
print(f"Delta: {call_greeks['delta']:.4f}, Vega: {call_greeks['vega']:.4f}")
# Monte Carlo pricing with antithetic variates and parallel execution
mc = MonteCarloOptionPricer()
mc_result = mc.price_european(
spot=100.0,
strike=100.0,
rate=0.05,
dividend=0.02,
volatility=0.20,
time=1.0,
option_type="call",
num_paths=100_000,
use_antithetic=True,
seed=7,
parallel=True,
)
print(f"MC price: {mc_result['price']:.2f} ± {mc_result['std_error']:.4f}")
# Historical Value at Risk on simulated P&L
rng = np.random.default_rng(seed=123)
pl = rng.normal(0.0, 0.02, size=10_000)
risk = RiskMetrics()
var = risk.var(pl, confidence_level=0.95, method="historical")
print(f"95% VaR: {var['var']:.4%}")from dervflow import MonteCarloEngine
import matplotlib.pyplot as plt
engine = MonteCarloEngine(seed=42)
paths = engine.simulate_gbm(
s0=100.0,
mu=0.05,
sigma=0.20,
T=1.0,
steps=252,
paths=2_000,
parallel=True,
)
plt.figure(figsize=(10, 6))
plt.plot(paths[:10].T)
plt.title("Sample GBM paths")
plt.xlabel("Time step")
plt.ylabel("Price")
plt.tight_layout()
plt.show()from dervflow import PortfolioOptimizer
import numpy as np
rng = np.random.default_rng(seed=0)
# Daily returns for four assets (252 trading days)
returns = rng.normal(loc=0.0005, scale=0.015, size=(252, 4))
optimizer = PortfolioOptimizer(returns)
min_weights = np.zeros(returns.shape[1])
max_weights = np.full(returns.shape[1], 0.6)
result = optimizer.optimize(
target_return=float(returns.mean(axis=0).mean()),
min_weights=min_weights,
max_weights=max_weights,
)
print("Optimal weights:", result["weights"])
print(f"Expected return: {result['expected_return']:.2%}")
print(f"Volatility: {result['volatility']:.2%}")
frontier = optimizer.efficient_frontier(num_points=10, min_weights=min_weights, max_weights=max_weights)
for point in frontier[:3]:
print(
f"Frontier portfolio → return: {point['expected_return']:.2%}, volatility: {point['volatility']:.2%}"
)from dervflow import YieldCurve, YieldCurveBuilder, BondAnalytics
import numpy as np
# Interpolate zero rates
times = np.array([0.5, 1.0, 2.0, 5.0, 10.0])
rates = np.array([0.020, 0.024, 0.028, 0.034, 0.038])
curve = YieldCurve(times, rates, method="cubic_spline_natural")
print(f"5Y discount factor: {curve.discount_factor(5.0):.6f}")
# Bootstrap from bond quotes (maturity, coupon, clean price, frequency)
bonds = [
(0.5, 0.02, 99.50, 2),
(1.0, 0.025, 99.80, 2),
(2.0, 0.030, 100.20, 2),
(5.0, 0.035, 101.10, 2),
]
builder = YieldCurveBuilder()
bootstrapped = builder.bootstrap_from_bonds(bonds)
print(f"2Y zero rate: {bootstrapped.zero_rate(2.0):.4%}")
analytics = BondAnalytics()
duration = analytics.duration(
yield_rate=0.032,
coupon_rate=0.03,
years_to_maturity=5.0,
frequency=2,
duration_type="modified",
)
print(f"Modified duration: {duration:.4f}")from dervflow import TimeSeriesAnalyzer
import numpy as np
prices = np.array([100.0, 102.0, 101.5, 103.0, 104.5, 103.8, 105.2])
analyzer = TimeSeriesAnalyzer(prices)
log_returns = analyzer.returns(method="log")
summary = analyzer.stat()
print(f"Mean: {summary['mean']:.5f}, Std Dev: {summary['std_dev']:.5f}")
acf = analyzer.autocorrelation(max_lag=5)
print("Autocorrelation (lags 0–5):", acf)The Rust crate can be used directly without the Python bindings. Enable the domains you need via feature flags:
use dervflow::options::analytical::black_scholes_price;
use dervflow::common::types::{OptionParams, OptionType};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let params = OptionParams::new(100.0, 100.0, 0.05, 0.02, 0.20, 1.0, OptionType::Call);
let price = black_scholes_price(¶ms)?;
println!("Call price: {:.2}", price);
Ok(())
}When depending on DervFlow from another Rust project, disable the default Python bindings and opt into the domains you require:
[dependencies]
dervflow = { path = "../dervflow", default-features = false, features = ["options", "numerical"] }- Install Rust (1.74 or newer recommended) and Python 3.10–3.14.
- Create/activate a virtual environment.
- Install the build backend:
pip install "maturin[patchelf]" - Build and install the extension in editable mode:
The command compiles the Rust sources with the
maturin develop --release
pythonfeature enabled and installs thedervflowpackage into the active environment.
If you only need the Rust APIs, compile without the Python bindings:
cargo build --no-default-features --features coreYou can further narrow the domains (for example --features options,portfolio) depending on your needs.
DervFlow exposes granular Cargo features:
| Feature | Enables |
|---|---|
python |
PyO3 bindings (pyo3, numpy) for the Python extension module. Enabled by default. |
core |
Umbrella that enables every domain-specific module listed below. Enabled by default. |
numerical |
Foundational numerical routines (integration, optimisation, random generation). |
options |
Option pricing engines and volatility analytics. Depends on numerical. |
risk |
Greeks aggregation, VaR/CVaR, and portfolio risk metrics. Depends on numerical. |
portfolio |
Mean-variance optimisation, efficient frontier, risk parity, Black–Litterman. |
yield_curve |
Yield-curve bootstrapping, interpolation, and bond analytics. Depends on numerical. |
timeseries |
Returns, rolling statistics, correlation diagnostics, GARCH models. |
monte_carlo |
Stochastic process simulators and Monte Carlo pricing. Depends on numerical. |
Run the full test suite locally before opening a pull request:
# Ensure PyO3 uses the intended interpreter
export PYO3_PYTHON="$(which python3)"
# Rust unit and integration tests (all domains + Python bindings)
cargo test --all-features
# Python tests (requires maturin develop)
pytest tests/python -v
# Linting and formatting
cargo fmt
cargo clippy --all-targets --all-features
black python/
mypy python/dervflowIf linking against CPython fails when building with the python feature, install the appropriate python3.x-dev package and export PYO3_PYTHON to the desired interpreter before invoking cargo.
If you use dervflow in your work and wish to refer to it, please use the following BibTeX entry.
@software{dervflow,
author = {Soumyadip Sarkar},
title = {DervFlow: A Lightweight, High-Performance Mathematics & Quantitative Finance Toolkit},
year = {2025},
url = {https://github.com/alphavelocity/dervflow}
}This project is licensed under the Apache License - see the LICENSE file for details.