Skip to content

Repository files navigation

DeltaCore

CI Python FastAPI NumPy Typing Quality

Production-minded Python backend for derivatives pricing, Greeks, volatility calibration, and market-risk analytics.

DeltaCore provides deterministic pricing and risk components for vanilla derivatives workflows. Pure pricing kernels sit behind typed API boundaries, with explicit model conventions and numerical checks against known references and invariants.

At A Glance

Area Current status
Pricing European call/put options under Black-Scholes and Bachelier
API FastAPI endpoints for pricing, Greeks, implied volatility, scenario PnL, and VaR/ES
Demo Browser demo at /demo, backed by live API calls
Greeks Analytic Black-Scholes delta, gamma, vega, theta, rho
Calibration Black-Scholes implied volatility with convergence diagnostics
Monte Carlo Black-Scholes European pricing with standard error and confidence interval
Risk Deterministic scenario PnL, historical VaR, and Expected Shortfall
Validation Closed-form fixtures, put-call parity, finite-difference Greeks
Quality Ruff formatting/linting, strict mypy, pytest
Roadmap Monte Carlo API endpoint and richer demo views

The distribution name is deltacore; the Python import namespace remains derivatives_risk_engine to keep the domain model explicit.

Use Case

Pricing services need model behavior that remains inspectable when numerical logic is exposed through an API. DeltaCore separates pure quantitative kernels from transport and orchestration so pricing, calibration, and risk calculations can be validated independently and reused consistently.

The implementation emphasizes:

  • formulas and conventions are documented in code and tests;
  • pricing functions are deterministic and side-effect free;
  • API contracts are typed with Pydantic;
  • tests favor references and invariants over visual demos.

Model Conventions

  • Black-Scholes uses lognormal spot dynamics, continuous risk-free and dividend rates, annualized volatility, and year-fraction time to expiry.
  • Bachelier uses a forward normal convention with F = S exp((r - q)T), risk-free discounting, and annualized normal volatility in price units.
  • Black-Scholes Greeks are analytic. Delta and gamma are spot-unit sensitivities, vega and rho use absolute volatility/rate bumps, and theta is calendar-time decay per year, equivalent to -dV/dT.
  • Black-Scholes implied volatility uses bounded one-dimensional root finding. Results report convergence, objective residual, iteration count, volatility bounds, and a structured failure reason when calibration is not possible.
  • Monte Carlo pricing uses the risk-neutral Black-Scholes terminal distribution, explicit random seeds, discounted payoff means, standard error, and a normal-approximation confidence interval.
  • Scenario PnL applies absolute shifts to spot, volatility, continuous rates, dividend yield, and time to expiry, then reprices under Black-Scholes. PnL is shocked_price - base_price.
  • Historical VaR and Expected Shortfall consume deterministic PnL observations where positive values are gains and negative values are losses. Loss is -PnL; VaR is the conservative empirical loss quantile, and ES is the mean of losses at or beyond that quantile.

Quickstart

uv sync --extra dev
uv run pytest

Run the full local quality gate:

uv run ruff format --check .
uv run ruff check .
uv run mypy src tests
uv run pytest

Use The Pricing Kernel

The Black-Scholes implementation assumes lognormal spot dynamics, continuous risk-free and dividend rates, annualized volatility, and time to expiry expressed as a year fraction. Inputs are deterministic and use no live market data.

from derivatives_risk_engine.core.instruments import EuropeanOption
from derivatives_risk_engine.core.market import BlackScholesMarket
from derivatives_risk_engine.models.black_scholes import black_scholes_price

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)
market = BlackScholesMarket(
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    volatility=0.20,
)

price = black_scholes_price(option, market)
print(price)  # 10.450583572185565

Use the Bachelier normal model:

from derivatives_risk_engine.core.instruments import EuropeanOption
from derivatives_risk_engine.core.market import BachelierMarket
from derivatives_risk_engine.models.bachelier import bachelier_price

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)
market = BachelierMarket(
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    normal_volatility=15.0,
)

price = bachelier_price(option, market)
print(price)  # 8.460134478825838

Compute Black-Scholes Greeks:

from derivatives_risk_engine.core.instruments import EuropeanOption
from derivatives_risk_engine.core.market import BlackScholesMarket
from derivatives_risk_engine.risk.greeks import black_scholes_greeks

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)
market = BlackScholesMarket(
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    volatility=0.20,
)

greeks = black_scholes_greeks(option, market)
print(greeks.delta, greeks.vega)

Solve Black-Scholes implied volatility:

from derivatives_risk_engine.calibration.implied_vol import (
    solve_black_scholes_implied_volatility,
)
from derivatives_risk_engine.core.instruments import EuropeanOption

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)

result = solve_black_scholes_implied_volatility(
    option=option,
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    target_price=10.450583572185565,
)

print(result.implied_volatility)  # 0.20
print(result.diagnostics.converged)

Run deterministic Monte Carlo pricing:

from derivatives_risk_engine.core.instruments import EuropeanOption
from derivatives_risk_engine.core.market import BlackScholesMarket
from derivatives_risk_engine.numerics.monte_carlo import monte_carlo_black_scholes_price

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)
market = BlackScholesMarket(
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    volatility=0.20,
)

result = monte_carlo_black_scholes_price(
    option=option,
    market=market,
    num_paths=50_000,
    seed=7,
)

print(result.price, result.standard_error)
print(result.confidence_interval_low, result.confidence_interval_high)

Run deterministic stress scenarios:

from derivatives_risk_engine.core.instruments import EuropeanOption
from derivatives_risk_engine.core.market import BlackScholesMarket
from derivatives_risk_engine.risk.scenario import (
    MarketShock,
    run_black_scholes_scenarios,
)

option = EuropeanOption(option_type="call", strike=100.0, time_to_expiry=1.0)
market = BlackScholesMarket(
    spot=100.0,
    risk_free_rate=0.05,
    dividend_yield=0.0,
    volatility=0.20,
)

results = run_black_scholes_scenarios(
    option,
    market,
    (
        MarketShock(name="spot_down_5", spot_shift=-5.0),
        MarketShock(name="vol_up_5_points", volatility_shift=0.05),
    ),
)

for result in results:
    print(result.scenario_name, result.pnl)

Estimate historical VaR and Expected Shortfall:

from derivatives_risk_engine.risk.var import historical_var_expected_shortfall

pnls = (12.0, 7.0, 5.0, 2.0, 0.0, -1.0, -3.0, -8.0, -10.0, -20.0)

result = historical_var_expected_shortfall(pnls, confidence_level=0.80)

print(result.value_at_risk)  # 8.0
print(result.expected_shortfall)  # 12.666666666666666

Try The API

Run the service:

uv run uvicorn derivatives_risk_engine.api.main:app --reload

Open the browser demo:

http://127.0.0.1:8000/demo

Current endpoints:

GET  /health
GET  /demo
POST /price/european
POST /greeks/european
POST /implied-volatility
POST /risk/scenario-pnl
POST /risk/historical-var
POST /price/european
curl -X POST http://127.0.0.1:8000/price/european \
  -H 'content-type: application/json' \
  -d '{
    "option_type": "call",
    "spot": 100.0,
    "strike": 100.0,
    "time_to_expiry": 1.0,
    "risk_free_rate": 0.05,
    "dividend_yield": 0.0,
    "volatility": 0.20
  }'
{
  "model": "black_scholes",
  "option_type": "call",
  "price": 10.450583572185565,
  "convention": "continuous_rates_annualized_volatility"
}

Architecture

flowchart LR
    API["FastAPI API"] --> Services["Service layer"]
    Services --> Core["Core instruments and market data"]
    Services --> Models["Pricing models"]
    Models --> Numerics["Numerical methods"]
    Services --> Risk["Risk analytics"]
Loading

Dependency direction is intentionally simple:

api -> services -> core/models/numerics/risk

Domain code does not depend on FastAPI. Pricing kernels stay pure and deterministic so they can be tested independently from transport concerns.

Numerical Validation

Check What it protects
Closed-form call fixture Black-Scholes call value under continuous rates
Closed-form put fixture Put sign convention and discounting
Bachelier fixtures Normal-model prices under forward-discounted convention
Put-call parity with dividends Internal consistency across calls and puts in both models
Analytic Greeks vs finite difference Delta, gamma, vega, theta, and rho conventions
Implied volatility inversion Recovers known vol and reports impossible prices
Monte Carlo confidence interval Fixed-seed simulation contains closed-form price
Scenario PnL repricing Shocked price equals direct Black-Scholes repricing
Historical VaR/ES Conservative loss quantile and tail-loss mean
Expiry intrinsic value Correct zero-time limiting behavior
API integration smoke test Pricing, Greeks, implied vol, risk endpoints, and demo page wiring

Roadmap

  • Bootstrap Python package, test layout, linting, typing, and FastAPI app.
  • Implement Black-Scholes European call/put pricing.
  • Validate with closed-form fixtures and put-call parity.
  • Add Bachelier pricing for normal-volatility workflows.
  • Add analytic and finite-difference Greeks.
  • Add implied-volatility solving with convergence diagnostics.
  • Add Monte Carlo pricing with confidence intervals.
  • Add scenario PnL and deterministic stress tests.
  • Add VaR and Expected Shortfall.
  • Expose Greeks, implied volatility, scenario PnL, and VaR/ES through API routes.
  • Add a rudimentary browser demo backed by the FastAPI endpoints.
  • Add Monte Carlo pricing to the API and enrich the demo with simulation uncertainty.

Project Boundaries

DeltaCore is not a live trading system and does not ingest market data. The current implementation is a validated backend slice for vanilla European option pricing, Black-Scholes Greeks, Black-Scholes implied-volatility inversion, and Monte Carlo pricing with confidence intervals, plus deterministic scenario PnL and historical VaR/Expected Shortfall. A lightweight browser demo is available at /demo and calls the same FastAPI endpoints exposed to external clients. Exotic products, calibration surfaces, Monte Carlo API exposure, and broader market-risk workflows are planned milestones and will be documented with explicit assumptions as they are implemented.

About

Validated Python API for derivatives pricing, Greeks, calibration, and market risk

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages