A platform for distributed quantitative computing designed for firms that already have working models and refuse to rewrite them.
DistributeQL solves the core dilemma facing small-to-mid-sized quantitative teams: how to scale battle-tested, thread-unsafe C++ libraries like QuantLib across a cluster and expose them to modern cloud workflows and AI agents—without incurring the multi-month delay and numerical discrepancy risk of a ground-up rewrite.
The Problem: QuantLib at Scale
Most quantitative teams at boutique hedge funds, prop desks, and risk consultancies rely on QuantLib or custom in-house numerical engines. When bringing these engines into distributed environments, three technical roadblocks appear:
- QuantLib is fundamentally thread-unsafe. Global singletons (such as
Settings::instance().evaluationDate()) and shared index structures mean multiple threads entering the library simultaneously will corrupt state or segfault. Multi-threaded microservices quickly fail under load. - The “Rewrite Trap.” Migrating pricing models to new cloud-native languages or heavy commercial frameworks costs months of engineering and risks subtle pricing drift between the old model and the new one.
- The AI Readiness Gap. Quantitative analysts want LLM agents (Claude, ChatGPT) to analyze portfolio risk and scenario pricing. But without a deterministic compute bridge, AI agents hallucinate formulas rather than calculating against the firm’s genuine yield curves and volatility surfaces.
DistributeQL resolves this with an architectural separation: a C++20 broker that enforces concurrency limits by isolating thread-unsafe calculations into dedicated worker processes, governed by two simple JSON contracts.
Crucially, it includes qlext—a pre-built, production-tested QuantLib Extension layer for JSON-RPC and MCP. Instead of spending months writing JSON converters, schedule builders, and date parsers for QuantLib’s hundreds of C++ classes, firms can reuse qlext directly, cutting application migration effort from quarters to days.
The Reusable QuantLib Extension (qlext): Drop-In JSON-RPC & MCP
QuantLib is an industry standard, but it was designed in the early 2000s without any concept of JSON serialization, REST APIs, or AI tool calling. Building a modern web or RPC wrapper around QuantLib from scratch typically requires writing thousands of lines of tedious boilerplate: mapping date strings to QuantLib::Date, constructing term structure handles, serializing coupon schedules, and managing global evaluation dates.
DistributeQL includes qlext (in both C++ and Python)—a battle-tested extension layer that converts QuantLib into a clean, modern JSON-RPC and MCP engine out of the box:
1. Zero Boilerplate Serialization & Deserialization
qlext provides pre-built handlers for the entire QuantLib instrument and curve hierarchy:
- Bonds & Fixed Income: Fixed rate, floating rate, zero-coupon, and callable bonds with complete yield/accrued/schedule mapping.
- Rates & Swaps: Vanilla IRS, Basis swaps, OIS, Zero-coupon swaps, YoY & Zero-coupon Inflation swaps (YYI/ZCI), and FRAs.
- Options & Volatility: European/American equity options, swaptions, caps/floors, vol surface sampling, and SABR / Hull-White calibration.
- Credit: Single-name CDS, recovery sensitivities, and hazard rate curve bootstrapping.
- Market Data & Conventions: 70+ international financial market calendar files and day-count convention parsers.
2. Built-in EvalDateGuard (Safe Evaluation Date Management)
QuantLib relies on a global singleton for pricing dates (Settings::instance().evaluationDate()). qlext encapsulates this with an RAII EvalDateGuard:
// qlext automatically sets request as-of date and restores state upon scope exit
struct EvalDateGuard {
QuantLib::Date saved;
explicit EvalDateGuard(const QuantLib::Date& asOf)
: saved(QuantLib::Settings::instance().evaluationDate()) {
QuantLib::Settings::instance().evaluationDate() = asOf;
}
~EvalDateGuard() {
QuantLib::Settings::instance().evaluationDate() = saved;
}
};
Every pricing request is evaluated against its exact scenario date without leaking state to subsequent calculations.
3. Reusing qlext to Minimize Existing Application Migration
If your firm has existing QuantLib code inside internal libraries, monolithic C++ trading systems, or Excel add-ins:
- Do not rewrite your analytics: Simply link against
qlextor adapt its modular handlers. - Immediate JSON-RPC: Your calculations immediately become callable over standard HTTP JSON-RPC without manual parsing logic.
- Immediate MCP Tools: Because
qlextdefines clean schemas, every instrument maps 1:1 into the Model Context Protocol (MCP) server catalogue. Your existing QuantLib models become instant tools for AI agents (Claude, Cursor, Copilots) on day one.
What It Is
DistributeQL is three things:
- A server (broker) that routes pricing tasks to worker processes, verifies caller identities, and guarantees thread-unsafe engines are never entered concurrently.
- Two contracts—one for workers, one for clients—both simple enough to understand in minutes.
- Twenty-five built-in pricing and risk workers, plus client libraries across six languages. These provide an immediate reference implementation and functional baseline.
The fundamental rule:
A worker is a table of functions. Each takes JSON and returns JSON.
A client is three HTTP calls.
The Worker Contract
A worker process loads plugins as shared modules. A plugin exposes named methods. A method takes parameters as JSON and returns a result as JSON. That is all a plugin ever sees—no networking, no socket management, no threading locks.
The identical contract exists across five languages:
| Language | The Contract | Use Case |
|---|---|---|
| C++ | DISTRIBUTEX_PLUGIN_METHODS({"name", fn}) over json(const json&) | QuantLib, native in-house C++ pricing engines, vendor .so |
| Python | get_methods() -> {"name": callable(dict) -> dict} | NumPy/SciPy analytics, ML models, rapid prototyping |
| Java | Map<String, Function<JsonNode, JsonNode>> getMethods() | Existing JVM analytics or enterprise risk services |
| C# | Dictionary<string, Func<JsonNode, JsonNode>> GetMethods() | .NET trading platforms and desktop tools |
| VBA | GetMethods() -> Scripting.Dictionary of name → procedure | In-house workbook models running directly inside Excel |
No IDL, no code generation, no schema compilation. A model already written in any of these languages joins the cluster by being wrapped, not ported.
C++ — Wrapping QuantLib Safely
Here is a complete C++ plugin wrapping a bond discount factor:
#include <cmath>
#include <nlohmann/json.hpp>
#include "../worker_plugin_interface.h"
json price_zero_coupon(const json& params) {
try {
// Required inputs use .at(), so missing parameters raise an exception
// and return a clean error result — never crashing the worker process.
const double notional = params.at("notional").get<double>();
const double rate = params.at("rate").get<double>();
const double years = params.at("years").get<double>();
// Optional inputs get a documented fallback.
const double spread = params.value("spread", 0.0);
const double df = std::exp(-(rate + spread) * years);
return {{"pv", notional * df}, {"discount_factor", df}};
} catch (const std::exception& e) {
// A failed calculation is a RESULT. Return it; do not throw past the host.
return {{"error", std::string("price_zero_coupon: ") + e.what()}};
}
}
// Registration macro: expose methods to the host
DISTRIBUTEX_PLUGIN_METHODS(
{"price_zero_coupon", price_zero_coupon}
)
Compile it as a shared module and drop it into the worker’s plugin directory:
add_library(my_curve MODULE cpp/worker/plugins/my_curve.cpp)
target_link_libraries(my_curve PRIVATE nlohmann_json::nlohmann_json)
set_target_properties(my_curve PROPERTIES PREFIX "" OUTPUT_NAME "my_curve")
sync_binary(my_curve "workers/cpp/plugins")
Link whatever you need—QuantLib, OpenGamma, proprietary analytics, or vendor libraries. The worker process treats the engine as a black box.
Python — For NumPy & Statistical Routines
"""my_analytics.py — drop directly into the worker's plugins directory."""
from typing import Any, Dict
import numpy as np
def portfolio_beta(params: Dict[str, Any]) -> Dict[str, Any]:
asset = params.get("asset_returns")
market = params.get("market_returns")
if not isinstance(asset, list) or not isinstance(market, list):
return {"error": "'asset_returns' and 'market_returns' must be lists"}
if len(asset) != len(market):
return {"error": f"length mismatch: {len(asset)} vs {len(market)}"}
if len(asset) < 2:
return {"error": "need at least two observations"}
a, m = np.asarray(asset, float), np.asarray(market, float)
# Both estimators use ddof=1 to avoid variance distortion
variance = float(np.var(m, ddof=1))
if variance == 0.0:
return {"error": "market returns have zero variance; beta is undefined"}
return {
"beta": float(np.cov(a, m, ddof=1)[0, 1] / variance),
"observations": len(a),
}
def get_methods():
return {"portfolio_beta": portfolio_beta}
No compilation. The Python worker scans the directory, imports get_methods(), and registers the capabilities automatically.
The Two Rules Every Worker Follows
- Answer every call, including errors. A bad input or numerical exception must return
{"error": "..."}. A client must never hang waiting for a timeout because an uncaught exception terminated the process. - Declare execution thread-safety explicitly. Configured in the worker’s JSON file:
{
"topic": "curves",
"execution": {
"thread_safety": "unsafe",
"concurrency": "serial"
}
}
- Declare
"safe"and"pooled": the worker process spawns worker threads to handle multiple concurrent calculations simultaneously. - Declare
"unsafe"and"serial": the server enforces strict serial execution on that worker process. This is mandatory for QuantLib plugins. To increase throughput for thread-unsafe libraries, you spin up additional worker processes rather than threads. The broker prevents any worker declaredunsafefrom running multi-threaded pools.
The Client Contract
Calling a model requires three standard HTTP requests. No proprietary client SDK is mandatory:
# 1. Authenticate once. Reuse the token across requests.
TOKEN=$(curl -s -X POST $DX/auth/client/login \
-H 'Content-Type: application/json' \
-d '{"id":"risk_desk","credential":"..."}' | jq -r .token)
# 2. Submit task. Returns immediately with an asynchronous request ID.
REQ=$(curl -s -X POST $DX/push-pull/request \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"topic":"curves","method":"price_zero_coupon",
"params":{"notional":1000000,"rate":0.04,"years":5}}' | jq -r .request_id)
# 3. Poll for the result. Returns 202 while pending, 200 with result when complete.
curl -s $DX/push-pull/result/$REQ -H "Authorization: Bearer $TOKEN"
# {"status":"success","result":{"pv":818730.75,"discount_factor":0.81873}}
The client does not know or care whether the worker was executed by C++, Python, or Java, or which server in the cluster ran it.
Direct Excel / Spreadsheet Integration
Portfolio managers and risk officers often live in Excel. DistributeQL connects to workbooks through custom worksheet functions via a lightweight VBA client:
=DX_BOND_DV01(100, 0.04, 0.035, 2, 10) ' Returns 0.0858
=DX_OPTION_GREEK(100, 105, 0.01, 0.2, "2027-06-30", "call", "delta")
Errors appear as readable text in the cell (e.g., DX error: 'yield' is required and must be a number) rather than #VALUE!. Desks can offload heavy portfolio pricing from their local Excel process to the Linux cluster without altering their spreadsheet workflow.
Making Models AI-Ready: Model Context Protocol (MCP)
DistributeQL bridges quantitative models directly into LLMs via Anthropic’s Model Context Protocol (MCP). Instead of relying on an AI model to approximate complex option math, the agent queries your firm’s real pricing methods as deterministic tools.
When a portfolio manager asks Claude Desktop or an AI copilot about risk:
User: “What happens to our 3-leg SPX option book if spot moves to 103?”
The agent authenticates with DistributeQL, calls the pricing tools, and responds with exact calculations:
Claude: “I repriced all three legs across your cluster at spot 103:
- Net Delta = −12.33 shares (the book is delta-flat).
- Net Vega = +$482.99 per vol point.
- Net P&L = −$10.57.
Note: The Delta-Gamma second-order approximation predicted −$9.93. The $0.64 variance reflects third-order curvature, confirming the full reprice was necessary. The position is primarily long vega; spot moves are secondary.”
Security Boundary: The LLM agent operates under standard client credentials. It has zero shell access, zero filesystem access, and can only execute the specific calculation topics granted in its registry identity.
Built-in Capability Reference (25 Working Calculations)
DistributeQL includes 25 reference calculations across six key asset classes:
| Asset Class | Included Capabilities |
|---|---|
| Equity Options | European and American pricing; full Greek suite (Delta, Gamma, Vega, Theta, Rho) returned in a single call. |
| FX Options | Garman-Kohlhagen pricing, implied volatility solver, full spot × volatility risk grids in one round-trip. |
| Bonds | Clean/dirty price, YTM, modified duration, convexity, key rate durations, effective risk. |
| Rates | Interest rate swap NPV, par swap rate, floating annuity, DV01 risk. |
| Credit | CDS pricing, CS01, recovery sensitivity, credit curve hazard rate bootstrapping. |
| Portfolio Risk | Historical, parametric, and Monte Carlo VaR with Expected Shortfall (CVaR); component risk attribution; stress scenarios; scenario revaluation. |
Pluggable Messaging Brokers: In-Memory, Redis, and NATS
DistributeQL does not lock you into a single transport or queue technology. The broker engine is fully pluggable (IBroker interface), allowing you to switch backends with a single configuration line:
| Broker Plugin | Architecture & Semantics | Best For |
|---|---|---|
In-Memory Broker (in_memory_broker.so) | Default. Zero external dependencies, lock-free queues, minimal dispatch latency. In-flight requests live in memory. | Local desk deployment, unit testing, development, and low-latency single-box setups. |
Redis Broker (redis_broker.so) | Distributed queueing via Redis lists and BLPOP. Features in-flight message tracking, consumer visibility timeouts, and automatic nack / redelivery: if a worker process crashes mid-task, the request is re-queued rather than lost. | Multi-machine production clusters, high availability, and resilient worker failover. |
NATS Broker (nats_broker.so) | High-throughput distributed pub/sub and request-reply over NATS. Includes automatic reconnection and re-subscription loops. | Cloud-native multi-node clusters, cross-datacenter routing, and microservice meshes. |
In addition to standard HTTP/REST, clients can stream results via Server-Sent Events (sse_client) or communicate directly over message queues (mq_client).
Real Benchmark Numbers
We report real, measured performance numbers from single-machine testing:
Test Run: 54,120 option repricings driven by a test client:
- 1 pricing worker: 10.07 seconds
- 3 pricing workers: 7.94 seconds (1.27× speedup)
The Honest Interpretation
A standard Black-Scholes evaluation takes under a millisecond. In a single-client loop, the test client’s HTTP request pipeline saturates before three workers do.
Adding worker processes yields linear speedups where heavy load actually exists:
- Computationally intensive analytics: High-path Monte Carlo simulations, multi-curve bootstrapping, and historical VaR.
- Concurrent client load: Multiple traders, risk reporting engines, and Excel workbooks submitting batches concurrently.
If an operation is network round-trip bound rather than compute bound, adding hardware is ineffective. Instead, use batch methods: for instance, DistributeQL’s FX risk grid prices an entire spot-by-volatility matrix in a single request.
What It Does Not Do: Engineering Boundaries
A platform you cannot verify is a platform you should not rely on. We are explicit about our architectural boundaries:
- Broker State Depends on the Plugin: The default in-memory broker is ephemeral (requests are lost if the broker itself crashes). If your deployment requires durable queues and worker failure recovery, enable the Redis broker plugin, which tracks inflight tasks and re-queues orphaned requests.
- TLS Terminates Upstream: The server does not handle TLS termination directly. Deploy behind a standard reverse proxy (Nginx, Caddy, or Envoy) in production.
- Plugins Execute Native Code: Loading a
.soor.dllexecutes native code in the worker process by design. Access to the plugin directory must be secured with standard filesystem permissions. - Thread Safety is a Configuration Promise: The broker guarantees strict serial execution if a worker is marked
"unsafe". However, the broker cannot inspect your C++ source code—if you mark a stateful singleton library as"safe", concurrency bugs remain your responsibility.
Getting Started: Free Binaries & Consulting
1. Free Developer Evaluation Package
Evaluate DistributeQL on your local development machine with zero cost or commitment:
- Pre-compiled Linux x86_64 broker and worker binaries.
- Reference C++, Python, and Excel VBA plugins.
- Built-in 25 pricing and risk calculations.
- Native Model Context Protocol (MCP) server binary.
- Full client integration examples (Python, C++, Excel VBA).
Demo

Sample Admin

You can stand up a test broker, wrap an existing model, and call it from an Excel cell or Python script in an afternoon.
→ Download Free Binaries & Sample Code
2. Consulting Engagements & Full Source Code Access
For boutique hedge funds, family offices, and quant teams seeking enterprise deployment or custom architectural support:
- Full Source Code License: Access to the complete modern C++20 broker codebase, SDKs, and plugin interfaces.
- QuantLib Model Migration: Hands-on assistance wrapping proprietary C++, Python, or legacy spreadsheet analytics into distributed workers.
- Infrastructure & Concurrency Profiling: Designing on-premise or private cloud topologies tailored to your firm’s specific calculation profiles (thread-safe math vs. serial QuantLib workers).
- AI Copilot Setup: Customizing the Model Context Protocol tools for internal risk desks using Claude or local LLMs.
To discuss an engagement, reach out to the author directly via LinkedIn (Wenhua W.).