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)
for outcome in result.account_pnls:
    print(f"account P&L outcome for {outcome.account_id}")
for outcome in result.account_adjustments:
    print(f"account adjustment from group {outcome.policy_group_id}")

# 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.7.0.tar.gz (572.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.7.0-cp310-abi3-win_amd64.whl (893.3 kB view details)

Uploaded CPython 3.10+Windows x86-64

openpit-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl (961.0 kB view details)

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

openpit-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (961.6 kB view details)

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

openpit-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (925.5 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

openpit-0.7.0-cp310-abi3-macosx_11_0_arm64.whl (855.5 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

openpit-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl (921.8 kB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: openpit-0.7.0.tar.gz
  • Upload date:
  • Size: 572.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.7.0.tar.gz
Algorithm Hash digest
SHA256 56d6f5d4f3a7366a31711f68a602fe9114cccbb5ebb85060f9ea584cafeb8b3a
MD5 8acbbdb1daa886f33bb9786a82a1e42e
BLAKE2b-256 09473172cee7ba45d2b85edc4b74b6dd198778c9cc7a12a9a2c5f69c344c7237

See more details on using hashes here.

File details

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

File metadata

  • Download URL: openpit-0.7.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 893.3 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.7.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ed4c99f4bcae63f1137d65927596f63b80bb4abc2f3d2b551b9e490fd8bd73e2
MD5 b8ab99b376cd33630de7231981cc571f
BLAKE2b-256 de7422160261f1bf361ee28b289dfbdbbe46b78bce59e17505861149ab57b38a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for openpit-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 a460b56ab3e00ef51c38a4e902757acaee9d7da4530542e7d2131abdf335fc72
MD5 92433c944df6896b8ade8364ce35cb5f
BLAKE2b-256 9caa7bf485e98bb225c5862c46906c897f5ce7237c52de396b878c31b5262fac

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for openpit-0.7.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eb9a7f9feead23ffed75598ca3459b08b3b1b0913ac348488693b17401c19dbd
MD5 fa9f14983b5e2724c731ecf478dd05d5
BLAKE2b-256 738232ecd9ff1a2038d49adf5ab49e845fe28076e323a588a00f5620bde5bb6a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for openpit-0.7.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e13292ce27241cad4e7f4435031c60bdd1a80f8f259f8891b36c8fb2bef6cac8
MD5 d86d2587be5771fc5517351117aba375
BLAKE2b-256 db624c94f969e7d8cc751ca890255dc8f298c9bad74a075666af8f5fbd3486e0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for openpit-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 584fe9334e3fd8532e8ba91526407fa0b5f2ec2269ac8978c53e108e60dfdf01
MD5 4115515ac83c5a30619966d3cbac5413
BLAKE2b-256 7a57ba4805d0cbeb8845d0eeef03442269f569f4f32f1d4877dd3fd11a538de9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for openpit-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e1162bd46363b05da4987037279f9aec2d745093405723f80518b6f284d2cb58
MD5 bd08292b7071096623f84a394b353b57
BLAKE2b-256 2d3e8ff3d55770a6f6b056f2deab1f9d3227d5f8e261e09a0b99d8f25d975743

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