Skip to main content

Embeddable pre-trade risk SDK

Project description

OpenPit (Pre-trade Integrity Toolkit) for Python

Verify Release Python versions PyPI License

openpit is an embeddable pre-trade risk SDK for integrating policy-driven risk checks into trading systems from Python.

For an overview and links to all resources, see the project website openpit.dev. For the Python API guide and reference, see openpit.readthedocs.io. For full project documentation, see the repository README. For conceptual and architectural pages, see the project wiki.

Versioning Policy (Pre‑1.0)

Before the 1.0 release OpenPit follows a relaxed Semantic Versioning:

  • PATCH releases carry bug fixes and small internal corrections.
  • MINOR releases may introduce new features and may also change the public interface.

Breaking API changes can appear in minor releases before 1.0. Pick version constraints that tolerate API evolution during the pre-stable phase.

Getting Started

Visit the PyPI package.

Examples

Runnable end-to-end examples live in examples/python/:

Install

For normal end-user installation, use the published PyPI package:

pip install openpit
POSIX (Linux, macOS, etc)

Install Rust and Python 3.10+. Just is optional but recommended.

If you need local development/debugging, clone this repository and build from source with Maturin:

With Just:

just python-develop-debug

Local release build:

just python-develop-release

Manual:

python3 -m venv .venv
.venv/bin/python -m pip install -r ./requirements.txt
.venv/bin/python -m maturin develop --manifest-path bindings/python/Cargo.toml
.venv/bin/python -m maturin develop --release --manifest-path bindings/python/Cargo.toml
Windows

Install rustup, target x86_64-pc-windows-msvc, and Python 3.10+. Just is optional but recommended.

With Just:

rustup target add x86_64-pc-windows-msvc
just python-develop-debug
just python-develop-release

Manual:

rustup target add x86_64-pc-windows-msvc
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r .\requirements.txt
.\.venv\Scripts\python.exe -m maturin develop `
  --manifest-path bindings/python/Cargo.toml `
  --target x86_64-pc-windows-msvc
.\.venv\Scripts\python.exe -m maturin develop `
  --release `
  --manifest-path bindings/python/Cargo.toml `
  --target x86_64-pc-windows-msvc

Engine

Overview

The engine evaluates an order through a deterministic pre-trade pipeline:

  • engine.start_pre_trade(order=...) runs lightweight start-stage checks
  • request.execute() runs main-stage check policies
  • reservation.commit() applies reserved state
  • reservation.rollback() reverts reserved state
  • engine.apply_execution_report(report=...) updates post-trade policy state

Start-stage checks aggregate rejects from all registered policies. Main-stage checks aggregate rejects and run rollback mutations in reverse order when any reject is produced.

Built-in policies:

The primary integration model is to write project-specific policies against the public Python policy API: Custom Python policies.

Threading

Canonical contract: Threading Contract.

Public methods acquire the GIL when needed; the SDK does not release the GIL across callback boundaries, so Python policies execute on the calling thread.

Custom policies that need internal state across calls can use the built-in Storage abstraction. In typical Python usage (synchronous code or an asyncio loop pinned to one thread) the no-sync policy is sufficient and the storage compiles down to direct dictionary access. A synchronizing policy is needed only when the engine is genuinely shared across OS threads.

Usage

import datetime
import openpit
import openpit.pretrade.policies

# 1. Configure policies.
pnl_policy = (
    openpit.pretrade.policies.build_pnl_bounds_killswitch()
    .broker_barriers(
        openpit.pretrade.policies.PnlBoundsBrokerBarrier(
            settlement_asset="USD",
            lower_bound=openpit.param.Pnl("-1000"),
        ),
    )
)

rate_limit_policy = (
    openpit.pretrade.policies.build_rate_limit()
    .broker_barrier(
        openpit.pretrade.policies.RateLimitBrokerBarrier(
            limit=openpit.pretrade.policies.RateLimit(
                max_orders=100,
                window=datetime.timedelta(seconds=1),
            ),
        ),
    )
)

max_qty = openpit.param.Quantity("500")
max_notional = openpit.param.Volume("100000")
order_size_policy = (
    openpit.pretrade.policies.build_order_size_limit()
    .broker_barrier(
        openpit.pretrade.policies.OrderSizeBrokerBarrier(
            limit=openpit.pretrade.policies.OrderSizeLimit(
                max_quantity=max_qty,
                max_notional=max_notional,
            ),
        )
    )
    .asset_barriers(
        openpit.pretrade.policies.OrderSizeAssetBarrier(
            limit=openpit.pretrade.policies.OrderSizeLimit(
                max_quantity=max_qty,
                max_notional=max_notional,
            ),
            settlement_asset="USD",
        ),
    )
)

# 2. Build the engine (one time at the platform initialization).
engine = (
    openpit.Engine.builder()
    .no_sync()
    .builtin(openpit.pretrade.policies.build_order_validation())
    .builtin(pnl_policy)
    .builtin(rate_limit_policy)
    .builtin(order_size_policy)
    .build()
)

# 3. Check an order.
order = openpit.Order(
    operation=openpit.OrderOperation(
        instrument=openpit.Instrument("AAPL", "USD"),
        account_id=openpit.param.AccountId.from_int(99224416),
        side=openpit.param.Side.BUY,
        trade_amount=openpit.param.TradeAmount.quantity(100.0),
        price=openpit.param.Price(185.0),
    ),
)

start_result = engine.start_pre_trade(order=order)

if not start_result:
    messages = ", ".join(
        f"{r.policy} [{r.code}]: {r.reason}: {r.details}"
        for r in start_result.rejects
    )
    raise RuntimeError(messages)

request = start_result.request

# 4. Quick, lightweight checks, such as fat-finger scope or enabled kill
# switch, were performed during pre-trade request creation. The system state
# has not yet changed, except in cases where each request, even rejected ones,
# must be considered. Before the heavy-duty checks, other work on the request
# can be performed simply by holding the request object.

# 5. Real pre-trade and risk control.
execute_result = request.execute()

# Optional shortcut for the same two-stage flow:
# execute_result = engine.execute_pre_trade(order=order)

if not execute_result:
    messages = ", ".join(
        f"{reject.policy} [{reject.code}]: {reject.reason}: {reject.details}"
        for reject in execute_result.rejects
    )
    raise RuntimeError(messages)

reservation = execute_result.reservation

# 6. If the request is successfully sent to the venue, it must be committed.
# The rollback must be called otherwise to revert all performed reservations.
try:
    send_order_to_venue(order)
except Exception:
    reservation.rollback()
    raise

reservation.commit()

# 7. The order goes to the venue and returns with an execution report.
report = openpit.ExecutionReport(
    operation=openpit.ExecutionReportOperation(
        instrument=openpit.Instrument("AAPL", "USD"),
        account_id=openpit.param.AccountId.from_int(99224416),
        side=openpit.param.Side.BUY,
    ),
    financial_impact=openpit.FinancialImpact(
        pnl=openpit.param.Pnl("-50"),
        fee=openpit.param.Fee("3.4"),
    ),
)

result = engine.apply_execution_report(report=report)

# 8. After each execution report is applied, the system may report that it has
# been determined in advance that all subsequent requests will be rejected if
# the account status does not change.
assert not result.account_blocks

Errors

Policy rejects from engine.start_pre_trade() and request.execute() are returned as StartResult and ExecuteResult.

Input validation errors and API misuse still raise exceptions:

  • ValueError for invalid assets/sides/malformed numeric inputs
  • RuntimeError for lifecycle misuse, for example executing the same request twice or finalizing the same reservation twice
  • Business rejects use stable reject codes such as openpit.pretrade.RejectCode.ORDER_VALUE_CALCULATION_FAILED when a policy cannot evaluate order value without price

Local Testing

POSIX (Linux, macOS, etc)

Recommended local flow:

With Just:

just test-python-debug
just test-python-unit-debug
just test-python-integration-debug

Manual:

python3 -m venv .venv
.venv/bin/python -m pip install -r ./requirements.txt
.venv/bin/python -m maturin develop --manifest-path bindings/python/Cargo.toml
.venv/bin/python -m pytest bindings/python/tests

Run only unit tests:

.venv/bin/python -m maturin develop --manifest-path bindings/python/Cargo.toml
.venv/bin/python -m pytest bindings/python/tests/unit

Run only integration test:

.venv/bin/python -m maturin develop --manifest-path bindings/python/Cargo.toml
.venv/bin/python -m pytest bindings/python/tests/integration
Windows

Optional: Just.

With Just:

just test-python-debug
just test-python-unit-debug
just test-python-integration-debug

Manual:

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r .\requirements.txt
.\.venv\Scripts\python.exe -m maturin develop `
  --manifest-path bindings/python/Cargo.toml `
  --target x86_64-pc-windows-msvc
.\.venv\Scripts\python.exe -m pytest bindings/python/tests
.\.venv\Scripts\python.exe -m pytest bindings/python/tests/unit
.\.venv\Scripts\python.exe -m pytest bindings/python/tests/integration

For full build/test command matrix (manual and just), see the repository README.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openpit-0.6.0.tar.gz (527.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

openpit-0.6.0-cp310-abi3-win_amd64.whl (856.6 kB view details)

Uploaded CPython 3.10+Windows x86-64

openpit-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl (921.4 kB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ x86-64

openpit-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (924.6 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

openpit-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (891.1 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

openpit-0.6.0-cp310-abi3-macosx_11_0_arm64.whl (823.3 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

openpit-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl (882.8 kB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file openpit-0.6.0.tar.gz.

File metadata

  • Download URL: openpit-0.6.0.tar.gz
  • Upload date:
  • Size: 527.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for openpit-0.6.0.tar.gz
Algorithm Hash digest
SHA256 78e6764664d50fa6219ea63e2af272d1d94e138b63b2c6fd6588c6cb7909f03c
MD5 db382c881491a69a9756ab46a73ae0a5
BLAKE2b-256 706c40bb39b9a5fe24d215d5ea9c6032b39fa5694503cad92d07336aca523379

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: openpit-0.6.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 856.6 kB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for openpit-0.6.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 8c150df9e0c916cade47bb0c691034093da678c052447ee308fa33989e6b17a4
MD5 abedd8fdd12f6286445110113d1c3f84
BLAKE2b-256 d7b8b8fe4a7ba11c6f6b2e2c76e6abdc3bac830e714b8c57e27c6b44d8f1a30b

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for openpit-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8d22b89cfa8faa821c3435e9a9aa9d68983a88d68d478effa2ecd6054247b93b
MD5 2583bcc52b31b01099d9b2986aeca687
BLAKE2b-256 3cf26efe336752cf626c406f489de202f1afa82c6da2bc6ed7d3c57fa0b67197

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for openpit-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fce62ae1150d0d7400e10cc6457728a4b90bdc35a9e5966a35c4ab93ecfbc9f7
MD5 40460a7e4c95c4efe07c0ce980275628
BLAKE2b-256 9128e540e5b101827096bcc27ee1ba7b35425a3408ba62921b9ad5ea6acc6649

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for openpit-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 eedc4429c4d513344e3afbd58e52a31ed4d02fd566c5b09f092ad80f0bdc4d89
MD5 33c4f4a7bea84d15652e5b0365a42142
BLAKE2b-256 401221b2aba54f33a268ad73389868626606aab77f9577a36d31c026467db6b3

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for openpit-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c42871a19d7d0c7bca14544d213ac95362d7d0ea69fd9d2522d8602127a2230b
MD5 af0e01576b09ab900f5fccbd0d9e22d7
BLAKE2b-256 8521c760c0fd5270a11c5d164877cf75a193e1a9d1773cd1373a581dfe8cca12

See more details on using hashes here.

File details

Details for the file openpit-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for openpit-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1e61295dc6a9e9d6ccb5fc521a71da655244dc33f183570e7dda24b5e2cf7e5b
MD5 efedca67e36bb2ca33047cca6ef4d537
BLAKE2b-256 3ca7b76da0606838e2113a93e89d618b56b3459263c7069ee995578ffd71793b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page