pyvar-client
Python SDK for pyvar.com's open-source risk computation API — 385 functions across 8 domains, one typed client.
Status: v0.2.0-track, built ahead of its originally planned schedule (see
docs/pyvar_release_plan.mdin the main repo). Alpha — the API surface may still change before a 1.0 release.
Install
pip install pyvar-client
Quick start
from pyvar_client import Client
client = Client(api_key="eyJ...") # a JWT obtained via pyvar.com registration + email verification
result = client.market_risk.historical_simulation_var(
returns=[...], # historical daily log-returns
portfolio_value=1_000_000,
confidence_level=0.99,
)
print(result["var_pct"], result["var_abs"])
Or as a context manager, which closes the underlying connection pool on exit:
with Client(api_key="eyJ...") as client:
...
The one async function: Monte Carlo VaR
Every domain function is synchronous request/response — call it, get the result.
POST /var/compute is the one exception: it's a real Monte Carlo job dispatched
to pyvar's Celery/SQS worker fleet, so it returns a task_id immediately instead
of a result. client.var wraps that:
# Blocks: submits, polls until done, returns the finished result.
result = client.var.compute(
portfolio_value=1_000_000,
returns=[...],
n_simulations=100_000,
)
# Or drive it yourself:
task_id = client.var.submit(portfolio_value=1_000_000, returns=[...])
status = client.var.poll(task_id) # check once, no blocking
Above a simulation-count threshold, the API offloads the full loss distribution
to S3 and returns a presigned_url instead of the inline loss_dist — compute()
returns exactly what the API returned either way; fetching a presigned URL is a
plain httpx.get() if you want the raw distribution.
Errors
Every non-2xx response raises a typed exception, not a generic HTTP error:
| Exception | Status | Notes |
|---|---|---|
PyvarAuthError |
401 | Token missing, invalid, or expired. Register/verify at pyvar.com to get a new one — this client doesn't automate that flow. |
PyvarValidationError |
422 | .detail carries the field-level validation errors. |
PyvarRateLimitError |
429 | .retry_after (seconds) from the response's Retry-After header. |
PyvarComputeError |
— | A VaR job (client.var.compute) reached status="failure" server-side. .task_id and .detail. |
PyvarTimeoutError |
— | A VaR job didn't finish within poll_timeout_seconds. .task_id — poll it again later, the job may still complete. |
PyvarError |
any other 4xx/5xx | Base class for everything above; catch this if you just want "did it fail". |
from pyvar_client import Client, PyvarValidationError, PyvarRateLimitError
try:
client.market_risk.historical_simulation_var(returns=[...], portfolio_value=1_000_000)
except PyvarValidationError as e:
print(e.detail)
except PyvarRateLimitError as e:
print(f"retry after {e.retry_after}s")
Retries
Every synchronous domain function is idempotent (pure compute, no side effects) —
connection errors, timeouts, and 5xx responses are retried automatically with
exponential backoff. client.var.submit() is the one call that's never
auto-retried: retrying a job submission blindly risks double-submitting real
compute work, since the API has no idempotency-key mechanism to de-duplicate on.
Polling (client.var.poll()) is a read, so it retries normally.
Domains
client.market_risk, client.derivatives, client.credit_risk, client.portfolio,
client.operational_risk, client.liquidity_risk, client.alm, client.regulatory
— one namespace per domain, one method per function. See
portal/functions.json
in the main repo for the full, live list, or just use your editor's autocomplete —
every method is fully typed.
CLI
pip install pyvar-client also installs a pyvar command — stdlib argparse
only, no extra install step, no extras group. It's a thin, generic dispatcher
over the same Client namespaces above: pyvar <domain> <function> --params file.json resolves to client.<domain>.<function>(**params), so every
current and future method works without the CLI needing its own copy of the
385-method catalogue.
export PYVAR_API_KEY="eyJ..." # or pass --api-key on every call
pyvar market_risk historical_simulation_var --params-json \
'{"returns": [0.01, -0.02, 0.015], "portfolio_value": 1000000}'
# Or from a file, or piped in via stdin with --params -
pyvar market_risk historical_simulation_var --params params.json
Calling a function with neither --params nor --params-json prints its
docstring and signature instead of making a doomed API call with zero fields
— handy when you don't remember what a function needs:
$ pyvar market_risk historical_simulation_var --api-key "$PYVAR_API_KEY"
historical_simulation_var(*, returns: list[float] | list[list[float]], portfolio_value: float, ...) -> dict[str, Any]
Historical simulation VaR from empirical return distribution.
...
The one async function gets its own submit/poll/compute sub-subcommands,
matching client.var exactly:
pyvar var compute --params var_params.json # blocks: submit + poll + return
pyvar var submit --params var_params.json # returns immediately: {"task_id": "..."}
pyvar var poll <task_id> # checks once, no blocking
pyvar var compute --params var_params.json --poll-interval 1 --poll-timeout 60
Discover what's available without any credentials at all:
pyvar list-domains
pyvar list-functions --domain market_risk
Exit codes distinguish failure modes for scripting, mirroring the exception table above:
| Exit code | Meaning |
|---|---|
0 |
Success (or a docstring/help display) |
1 |
Bad input — unknown domain/function, malformed --params, missing/wrong keyword arguments, or any other non-auth/validation/rate-limit/compute API error |
2 |
PyvarAuthError (401) |
3 |
PyvarValidationError (422) — field errors printed to stderr |
4 |
PyvarRateLimitError (429) — retry_after printed to stderr |
5 |
PyvarComputeError / PyvarTimeoutError — task_id printed to stderr |
130 |
Interrupted (Ctrl-C) |
How the domain methods are generated
385 methods is too much to hand-maintain without drifting from the API (see
docs/p9-function-catalogue-reconciliation.md in the main repo for a real
instance of exactly that drift). pyvar_client/_generated/ is produced by
codegen/generate.py, which reads the live OpenAPI schema
(main.create_app().openapi()) directly — regenerate after any API schema
change:
python3 codegen/generate.py
This needs the main repo's own dependencies installed (it imports
main.create_app() directly), so run it from a checkout with requirements.txt
requirements-heavy.txtinstalled, not just this package's own runtime deps.
Development
pip install -e ".[dev]"
pytest -v --cov=pyvar_client --cov-report=term-missing
black --check --line-length 100 .
isort --check-only --profile black .
ruff check .
No real HTTP calls anywhere in the test suite — httpx.MockTransport intercepts
every request, so the real retry/error-mapping/auth logic runs against a handler
the tests control, never a live server. See tests/conftest.py.
License
Apache License 2.0 — see
LICENSE.
Same license as the main pyvar.com repository.
Release files for pyvar-client 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyvar_client-0.1.2.tar.gz | 96.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyvar_client-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 193.0 kB
Release files / pyvar_client-0.1.2.tar.gz
| Download URL | pyvar_client-0.1.2.tar.gz |
|---|---|
| Size | 96.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2afd6ad353eaf5a250067aa27404ea50c11aefcffe9e488110f9469c8f16916b
|
|
BLAKE2b-256 checksum How to use checksums |
285f62ae0b8c05f6292f2b821878e907188feff105b9ba58639eb143f49b9ee3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logRelease files / pyvar_client-0.1.2-py3-none-any.whl
| Download URL | pyvar_client-0.1.2-py3-none-any.whl |
|---|---|
| Size | 96.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f57d4ac650468538b38e9a6fe642af685e41d77c2025e87fa111cc4ba1707c31
|
|
BLAKE2b-256 checksum How to use checksums |
1d8692faef6a7f9294999ebe739ff065c52ec8d15cbfb44af72b7dfaf725ebe6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency log