Skip to content

Getting Started

Eugene Palchukovsky edited this page Mar 12, 2026 · 1 revision

Getting Started

Pit has two full public SDKs today:

This page uses the conceptual step names start stage, execute request, finalize reservation, and apply execution report in prose. Exact API names stay inside the code blocks.

Both SDKs follow the same operational flow:

  1. Build an engine once during application startup.
  2. Run the start stage for each order.
  3. Execute request if the start stage passes.
  4. Finalize reservation explicitly.
  5. Apply execution report after realized outcomes are known.

Install

Rust

cargo add openpit

Python

pip install openpit

Example: Build an Engine

Rust
use std::time::Duration;

use openpit::param::{Asset, Pnl, Quantity, Volume};
use openpit::pretrade::policies::{
    OrderSizeLimit,
    OrderSizeLimitPolicy,
    OrderValidationPolicy,
    PnlKillSwitchPolicy,
    RateLimitPolicy,
};
use openpit::{
    FinancialImpact, ExecutionReportOperation, OrderOperation,
    WithFinancialImpact, WithExecutionReportOperation,
};
use openpit::Engine;

# fn main() -> Result<(), Box<dyn std::error::Error>> {
type ExecutionReport = WithExecutionReportOperation<WithFinancialImpact<()>>;

let usd = Asset::new("USD")?;

let pnl_policy = PnlKillSwitchPolicy::new(
    (
        usd.clone(),
        Pnl::from_str("1000")?,
    ),
    [],
)?;

let rate_limit_policy = RateLimitPolicy::new(100, Duration::from_secs(1));

let size_policy = OrderSizeLimitPolicy::new(
    OrderSizeLimit {
        settlement_asset: usd.clone(),
        max_quantity: Quantity::from_str("500")?,
        max_notional: Volume::from_str("100000")?,
    },
    [],
);

let engine = Engine::<OrderOperation, ExecutionReport>::builder()
    .check_pre_trade_start_policy(OrderValidationPolicy::new())
    .check_pre_trade_start_policy(pnl_policy)
    .check_pre_trade_start_policy(rate_limit_policy)
    .check_pre_trade_start_policy(size_policy)
    .build()?;
# Ok(())
# }

The Rust SDK verifies policy-to-order compatibility at compile time through capability traits. A policy that declares O: HasTradeAmount + HasOrderPrice will not compile unless the order type satisfies both bounds. Custom order types gain capabilities either by implementing the traits directly or by using Deref to delegate to an OrderOperation base.

Python
import openpit

pnl_policy = openpit.pretrade.policies.PnlKillSwitchPolicy(
    settlement_asset=openpit.param.Asset("USD"),
    barrier=openpit.param.Pnl("1000"),
)

rate_limit_policy = openpit.pretrade.policies.RateLimitPolicy(
    max_orders=100,
    window_seconds=1,
)

order_size_policy = openpit.pretrade.policies.OrderSizeLimitPolicy(
    limit=openpit.pretrade.policies.OrderSizeLimit(
        settlement_asset=openpit.param.Asset("USD"),
        max_quantity=openpit.param.Quantity("500"),
        max_notional=openpit.param.Volume("100000"),
    )
)

engine = (
    openpit.Engine.builder()
    .check_pre_trade_start_policy(
        policy=openpit.pretrade.policies.OrderValidationPolicy(),
    )
    .check_pre_trade_start_policy(policy=pnl_policy)
    .check_pre_trade_start_policy(policy=rate_limit_policy)
    .check_pre_trade_start_policy(policy=order_size_policy)
    .build()
)

Example: Run an Order Through the Engine

Rust
use openpit::param::{Asset, Price, Quantity, Side, TradeAmount};
use openpit::{Instrument, OrderOperation};

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let order = OrderOperation {
    instrument: Instrument::new(
        Asset::new("AAPL")?,
        Asset::new("USD")?,
    ),
    side: Side::Buy,
    trade_amount: TradeAmount::Quantity(
        Quantity::from_str("100")?,
    ),
    price: Some(Price::from_str("185")?),
};

let request = match engine.start_pre_trade(order) {
    Ok(request) => request,
    Err(reject) => {
        eprintln!(
            "rejected by {} [{}]: {} ({})",
            reject.policy,
            reject.code,
            reject.reason,
            reject.details
        );
        return;
    }
};

let reservation = match request.execute() {
    Ok(reservation) => reservation,
    Err(rejects) => {
        for reject in &rejects {
            eprintln!(
                "rejected by {} [{}]: {} ({})",
                reject.policy,
                reject.code,
                reject.reason,
                reject.details
            );
        }
        return;
    }
};

reservation.commit();
# Ok(())
# }
Python
order = openpit.Order(
    operation=openpit.OrderOperation(
        instrument=openpit.Instrument(
            openpit.param.Asset("AAPL"),
            openpit.param.Asset("USD"),
        ),
        side=openpit.param.Side.BUY,
        trade_amount=openpit.param.Quantity("100"),
        price=openpit.param.Price("185"),
    ),
)

start_result = engine.start_pre_trade(order=order)
if not start_result:
    reject = start_result.reject
    raise RuntimeError(
        f"{reject.policy} [{reject.code}]: {reject.reason}: {reject.details}"
    )

execute_result = start_result.request.execute()
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
reservation.commit()

Example: Apply Post-Trade Feedback

Rust
use openpit::{
    FinancialImpact, ExecutionReportOperation, WithFinancialImpact,
    WithExecutionReportOperation,
};
use openpit::param::{Asset, Fee, Pnl, Side};
use openpit::Instrument;

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let report = WithExecutionReportOperation {
    inner: WithFinancialImpact {
        inner: (),
        financial_impact: FinancialImpact {
            pnl: Pnl::from_str("-50")?,
            fee: Fee::from_str("3")?,
        },
    },
    operation: ExecutionReportOperation {
        instrument: Instrument::new(
            Asset::new("AAPL")?,
            Asset::new("USD")?,
        ),
        side: Side::Buy,
    },
};

let result = engine.apply_execution_report(&report);
if result.kill_switch_triggered {
    eprintln!("halt new orders until the blocked state is cleared");
}
# Ok(())
# }
Python
report = openpit.ExecutionReport(
    operation=openpit.ExecutionReportOperation(
        instrument=openpit.Instrument(
            openpit.param.Asset("AAPL"),
            openpit.param.Asset("USD"),
        ),
        side=openpit.param.Side.BUY,
    ),
    financial_impact=openpit.FinancialImpact(
        pnl=openpit.param.Pnl("-50"),
        fee=openpit.param.Fee("3"),
    ),
)

result = engine.apply_execution_report(report=report)
if result.kill_switch_triggered:
    print("halt new orders until the blocked state is cleared")

Operational Notes

  • Pit is in-memory. Persistence belongs to the host system.
  • Pit does not route orders or talk to venues.
  • Pit does not calculate realized P&L from raw fills for you. The caller sends realized outcomes through execution reports.
  • One shared engine instance does not coordinate concurrent access for you.

Related Pages

Clone this wiki locally