ZenQuant

Hex.pmDocsLicense

Trading analytics for Elixir, as pure functions.

Black-Scholes pricing and implied volatility, options chain analytics (max pain, GEX walls, skew term structures, IV surfaces), funding rates, cash-and-carry basis, volatility estimators, risk metrics, position sizing, orderflow, and portfolio aggregation.

Every function takes plain maps and numbers and returns plain maps and tuples. No processes, no supervision tree, no I/O, no exchange client. You fetch the data however you like; ZenQuant does the math.

The only runtime dependency is Descripex, which powers the self-describing API surface.

Installation

def deps do
[
{:zen_quant, "~> 0.2.0"}
]
end

Requires Elixir ~> 1.18.

Quick Start

Every output below is a real return value, not a sketch.

Options pricing and greeks

inputs = %{
spot: 100.0,
strike: 100.0,
time_to_expiry_years: 0.25,
risk_free_rate: 0.05,
dividend_yield: 0.0,
volatility: 0.6
}
ZenQuant.Options.Pricing.price(:call, inputs)
# => {:ok, 12.480797612835424}
ZenQuant.Options.Pricing.greeks(:call, inputs)
# => {:ok, %{delta: 0.5759983410021886, gamma: 0.0130560458310534,
# vega: 19.5840687465801, theta: -25.756834320265295, rho: 11.27975912184586}}
# Solve for the volatility that reproduces a market price
ZenQuant.Options.Pricing.implied_volatility(:call, 12.5, Map.delete(inputs, :volatility))
# => {:ok, %{volatility: 0.6009805272333324, iterations: 31,
# residual: -4.5e-10, converged: true}}

Time is supplied directly in years — the module applies no calendar or trading-day count, so you choose the convention.

Options chain analytics

chain = %{
"BTC-31JAN26-84000-C" => %{open_interest: 100.0, raw: %{"gamma" => 0.00001}}
}
ZenQuant.Options.oi_by_strike(chain) # => %{84000.0 => 100.0}
ZenQuant.Options.max_pain(chain) # => {:ok, 84000.0}

Plus gex_by_strike/2, pin_magnets/2, gamma_flip/2, put_call_ratio/1, atm_iv/2, atm_iv_term_structure/3, moneyness_skew/3, expected_range/3, and ZenQuant.Options.Surface.build/1 for sparse IV surfaces.

Funding and basis

# Per-period funding rate -> annualized APR. The period is a caller argument,
# so venues with non-8h cadence are a value, not a hardcoded constant.
ZenQuant.Funding.annualize(0.0001) # => 0.1095 (10.95% APR at 8h funding)
ZenQuant.Funding.annualize(0.0001, 1) # => 0.876 (hourly funding)
ZenQuant.Basis.spot_perp(100_000.0, 100_250.0)
# => %{absolute: 250.0, percent: 0.25, direction: :contango}
ZenQuant.Basis.annualized(100_000.0, 100_250.0, 30)
# => 0.030416666666666665

Volatility

ZenQuant.Volatility.realized([100.0, 101.5, 99.8, 102.0, 100.5])
# => 0.019963912649687825
ZenQuant.MeanReversion.half_life([100.0, 101.0, 99.5, 100.2, 100.8, 99.9, 100.1])
# => {:ok, 0.448506999188226}

Also parkinson/1, garman_klass/1, yang_zhang/1, cone/2, iv_rank/2, iv_percentile/2, iv_vs_rv/2.

Portfolio greeks, risk, and sizing

positions = [%{delta: 0.5, gamma: 0.02, theta: -10.0, vega: 25.0, quantity: 10}]
ZenQuant.Greeks.position_greeks(positions)
# => %{delta: 5.0, gamma: 0.2, theta: -100.0, vega: 250.0}
ZenQuant.Risk.sharpe_ratio([0.01, -0.005, 0.02, 0.015, -0.01])
# => 0.4636004455717535
ZenQuant.Risk.max_position_size(100_000, risk_pct: 0.02, stop_distance_pct: 0.05)
# => 10000.0
ZenQuant.Sizing.kelly(0.6, 2.0) # => 0.19999999999999998

Orderflow

ZenQuant.Orderflow.cvd([%{side: "buy", amount: 1.5}, %{side: "sell", amount: 0.5}])
# => 1.0

Also cvd_delta/1 (per-trade series), vwap/1, imbalance/2, heatmap_points/2, footprint_cells/3, dom_level/2.

API Discovery

ZenQuant describes itself. You do not need to read the docs to find a function:

ZenQuant.describe() # 26 modules with purpose + function count
ZenQuant.describe(:funding) # every function in ZenQuant.Funding
ZenQuant.describe(:funding, :annualize) # params, returns, returns_example, errors, composes_with

Short names are the last module segment, lowercased: ZenQuant.PowerLaw:power_law, ZenQuant.Options.Deribit:deribit.

For runtime agents that want structured data rather than formatted docs:

ZenQuant.Funding.__api__() # all hints for a module
ZenQuant.Funding.__api__(:annualize) # hints for one function
ZenQuant.Manifest.build() # full manifest as a map

Static export for non-BEAM consumers: mix zen_quant.manifestapi_manifest.json.

SKILLS.md is the full agent guide — composition chains, param kinds, and gotchas.

Modules

Options — pricing & greeks

ModulePurpose
ZenQuant.Options.PricingBlack-Scholes-Merton price, analytic greeks, implied volatility solver
ZenQuant.GreeksPortfolio greeks aggregation and exposure — aggregates greeks from exchange data, does not compute them
ZenQuant.Options.ProbabilityTerminal risk-neutral probabilities from vertical spreads

Options — chain analytics

ModulePurpose
ZenQuant.OptionsMax pain, GEX by strike, pin magnets, gamma flip, OI, ATM IV, expected range
ZenQuant.Options.GammaWallsGEX wall computation with explicit dealer/customer side convention
ZenQuant.Options.SkewDeterministic term structures from normalized skew observations
ZenQuant.Options.SurfaceSparse implied-volatility surfaces from a pre-fetched chain
ZenQuant.Options.ZeroDTENear-expiry analytics: near strikes, theta acceleration, gamma exposure
ZenQuant.Options.BlockTradesBlock-trade aggregation — aggressor side preserved, never inferred from size
ZenQuant.Options.SnapshotStructured options briefing over a chain; sections fail independently
ZenQuant.Options.DeribitDeribit symbol parsing, chain fetch + enrich, DVOL, gamma walls

Rates & carry

ModulePurpose
ZenQuant.FundingFunding rates: annualized APR, trend, spikes, ranking, carry candidates
ZenQuant.BasisSpot/perp basis, annualized carry, futures curve, implied funding

Volatility & statistics

ModulePurpose
ZenQuant.VolatilityRealized, Parkinson, Garman-Klass, Yang-Zhang, cones, IV rank/percentile
ZenQuant.MeanReversionOrnstein-Uhlenbeck half-life estimation
ZenQuant.PowerLawBitcoin power law: fair value, z-score, support/resistance bands, forecast

Risk & sizing

ModulePurpose
ZenQuant.RiskSharpe, Sortino, Calmar, VaR, max drawdown, beta, concentration, stress test, liquidation headroom
ZenQuant.SizingKelly, fixed fractional, optimal f, anti-martingale, volatility-scaled
ZenQuant.PortfolioExposure aggregation, realized/unrealized PnL, position summaries

Market microstructure

ModulePurpose
ZenQuant.OrderflowCVD, VWAP, imbalance, heatmap, footprint, DOM level
ZenQuant.OrderBookShared order-book level contract — strict parsing, explicit errors on unknown shapes
ZenQuant.MMMarket making: fair value, inventory skew, spread calculator, fill rate
ZenQuant.ExecutionCross-venue best price, arbitrage detection, non-executing order split plans
ZenQuant.OrderStateImmutable order lifecycle: fills, VWAP accumulation, cancellation
ZenQuant.WSWebSocket health: stale check, reconnect metrics

Recording & backtesting

ModulePurpose
ZenQuant.Recorder.JSONLJSONL snapshot recording — encode, decode, append, stream, read_all
ZenQuant.Recorder.ReplayFiltered replay with optional speed delays
ZenQuant.BacktestDeterministic strategy evaluation over recorded data

Display helpers

ZenQuant.Helpers.Funding, ZenQuant.Helpers.Greeks, ZenQuant.Helpers.Risk — formatting for dashboards. Core modules never format for display.

Design Principles

For AI Agents

ZenQuant is built agents-first. Start with ZenQuant.describe(), then narrow with describe/1 and describe/2. All returns are structured data that composes directly into the next call. See SKILLS.md for composition chains, the :value vs :exchange_data param distinction, and known gotchas.

License

MIT — see LICENSE.