Embeddable pre-trade risk SDK
Project description
OpenPit (Pre-trade Integrity Toolkit) for Python
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 generated 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:
PATCHreleases carry bug fixes and small internal corrections.MINORreleases 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/:
spot_funds- simplest SpotFunds policy integration (limit-only).spot_table- table-driven test runner for the SpotFunds policy.rate_pnl_killswitch- rate-limit + P&L kill-switch supervisor.
Install
For normal end-user installation, use the published PyPI package:
pip install openpit
If you need local development/debugging, clone this repository and build from source with Maturin:
maturin develop --manifest-path bindings/python/Cargo.toml
Local release build:
maturin develop --release --manifest-path bindings/python/Cargo.toml
Engine
Overview
The engine evaluates an order through a deterministic pre-trade pipeline:
engine.start_pre_trade(order=...)runs lightweight start-stage checksrequest.execute()runs main-stage check policiesreservation.commit()applies reserved statereservation.rollback()reverts reserved stateengine.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:
SpotFundsPolicy- per-account solvency gate over spendable fundsOrderValidationPolicy- structural integrity checks on every orderRateLimitPolicy- throttle order flow per broker, asset, or accountOrderSizeLimitPolicy- fat-finger caps on quantity and notionalPnlBoundsKillSwitchPolicy- halt an account when realized P&L breaches bounds
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:
ValueErrorfor invalid assets/sides/malformed numeric inputsRuntimeErrorfor 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_FAILEDwhen a policy cannot evaluate order value withoutprice
Local Testing
Recommended local flow:
maturin develop --manifest-path bindings/python/Cargo.toml
python -m pytest bindings/python/tests
Run only unit tests:
maturin develop --manifest-path bindings/python/Cargo.toml
python -m pytest bindings/python/tests/unit
Run only integration test:
maturin develop --manifest-path bindings/python/Cargo.toml
python -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
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openpit-0.4.0.tar.gz.
File metadata
- Download URL: openpit-0.4.0.tar.gz
- Upload date:
- Size: 401.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf5afb5ef8fc98ba2559be71e61aa74ec56b2a992a3dceb6d6f3e4f4c7d63b29
|
|
| MD5 |
f741dfc2b40d6e1a6d97e4b7b23c6c19
|
|
| BLAKE2b-256 |
c061d4d4dffc2313b42285bc75bfcc9ec7c720691b6eff8c1779d60a6cb3535d
|
File details
Details for the file openpit-0.4.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 649.8 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e069943b11f33442834bfa0cc413bb9e6ca361ba9b3106dac259b9a0adf9614
|
|
| MD5 |
efce2735ccace320df645da79ea4a3fb
|
|
| BLAKE2b-256 |
03e4728b2184c6901412c82e812fd89ff74f07b2e6ccb67bab5bb69498440eb7
|
File details
Details for the file openpit-0.4.0-cp310-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 774.5 kB
- Tags: CPython 3.10+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e944c9df324e3fee75758cdd9d448028448096bea6ada303231dcbdad034996e
|
|
| MD5 |
5172d8ed4bae0a9e7fe45f4d56bed84c
|
|
| BLAKE2b-256 |
b38c7dafec926c798d19ba2a93a224eb5910b97f12baec743a7f9b19ccd4e240
|
File details
Details for the file openpit-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 775.3 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
439d74f5cf7bb4de161f2bd433c9fac27da4a799210f3b4f52a7bbdfa0074381
|
|
| MD5 |
4fc28e30c8e427287acff02c6374bc6d
|
|
| BLAKE2b-256 |
3ef6537227d12d170601f719f581378ebdc6333427e04245274d042560351b04
|
File details
Details for the file openpit-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 738.9 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2d9fc1d748b6ef32da6dd0de465456c3bc40cbd414e6ebe81bab6fd507326b3
|
|
| MD5 |
07c614271dafc532b3af6e7dcf5c0bcc
|
|
| BLAKE2b-256 |
5f51ed1394a021d93c927cc5b3ba120bbd115e17cd60fc01aeaa1a972dd92bcb
|
File details
Details for the file openpit-0.4.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 671.0 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0829647bd307a87ea2aa0c99d34b2a170626dc4768cd08cfec76107b3ba4be9c
|
|
| MD5 |
3dc62b67ae5deab2898d7b84d9501e87
|
|
| BLAKE2b-256 |
94be0445f19538cd8fe812e94f0076a6705bac4ccf16d65bdf3a5c675251a476
|
File details
Details for the file openpit-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: openpit-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 726.5 kB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d673997253e532a51e5181c9dd74cbbcdd44b124fa4d7abd145b9c87e7d5023
|
|
| MD5 |
99f144562e581c5fe5861ca77ff842f0
|
|
| BLAKE2b-256 |
df52220860d3e182783be762c6846b3046c456b8746c902ea00fc5208453636d
|