-
Notifications
You must be signed in to change notification settings - Fork 1
Domain Types
Pit uses domain-specific value types so that quantities, prices, fees, P&L, cash flow, and identifiers are not mixed accidentally.
| Concept | Meaning | Go | Python | Rust |
|---|---|---|---|---|
| AccountId | Type-safe account identifier | openpit/param.AccountID |
openpit.param.AccountId |
openpit::param::AccountId |
| Asset | Asset or currency identifier such as AAPL or USD
|
openpit/param.Asset |
openpit.param.Asset |
openpit::param::Asset |
| Side | Trade direction: buy or sell | openpit/param.Side |
openpit.param.Side |
openpit::param::Side |
| PositionSide | Hedge-mode leg: long or short | openpit/param.PositionSide |
openpit.param.PositionSide |
openpit::param::PositionSide |
| Quantity | Requested or filled size in instrument units | openpit/param.Quantity |
openpit.param.Quantity |
openpit::param::Quantity |
| Price | Signed per-unit price | openpit/param.Price |
openpit.param.Price |
openpit::param::Price |
| PnL | Realized profit or loss in the settlement asset | openpit/param.Pnl |
openpit.param.Pnl |
openpit::param::Pnl |
| Fee | Fee paid or rebate received in the settlement asset | openpit/param.Fee |
openpit.param.Fee |
openpit::param::Fee |
| Volume | Absolute monetary size of a trade order | openpit/param.Volume |
openpit.param.Volume |
openpit::param::Volume |
| Notional | Monetary position exposure: |price| × qty, used for margin and risk |
openpit/param.Notional |
openpit.param.Notional |
openpit::param::Notional |
| CashFlow | Signed cash movement | openpit/param.CashFlow |
openpit.param.CashFlow |
openpit::param::CashFlow |
| PositionSize | Signed exposure size | openpit/param.PositionSize |
openpit.param.PositionSize |
openpit::param::PositionSize |
| AdjustmentAmount | Signed account-adjustment payload variant (delta or absolute) |
openpit.AdjustmentAmount |
openpit.param.AdjustmentAmount |
openpit::param::AdjustmentAmount |
| PositionMode | Derivatives position accounting mode (netting or hedged) |
openpit/param.PositionMode |
openpit.param.PositionMode |
openpit::param::PositionMode |
| Leverage | Per-order leverage multiplier | openpit/param.Leverage |
openpit.param.Leverage and openpit.Leverage
|
openpit::param::Leverage |
| FillType | Execution-event classification such as trade or liquidation | Not exposed | openpit.param.FillType |
openpit::param::FillType |
| PositionEffect | Position action reported by the venue: open or close | openpit/param.PositionEffect |
openpit.param.PositionEffect |
openpit::param::PositionEffect |
AccountId is designed optimized for speed and costs. Two constructors are
available:
-
from_u64: zero cost, zero collision risk; preferred whenever the broker or venue assigns numeric account IDs. -
from_str: hashes the string with FNV-1a 64-bit; collisions are theoretically possible. Collision probability forndistinct account strings:Accounts P(at least one collision) 1 000 < 3 × 10⁻¹⁴ 10 000 < 3 × 10⁻¹² 100 000 < 3 × 10⁻¹⁰ 1 000 000 < 3 × 10⁻⁸ See http://www.isthe.com/chongo/tech/comp/fnv/ for the algorithm specification.
If collision risk is unacceptable, maintain your own collision-free string→u64 mapping (e.g. a registry or a database sequence) and pass the resulting integer to
from_u64.Empty and whitespace-only strings are rejected; all constructors return an error in that case.
| Type | Positive | Negative |
|---|---|---|
Pnl |
Profit | Loss |
Fee |
Fee paid | Rebate received |
CashFlow |
Inflow | Outflow |
PositionSize |
Long | Short |
Quantity, Volume, and Notional can never be negative.
Orders use a single trade amount field with context defined by its type
where the target technology supports that shape. Otherwise, integrations may
expose two separate fields/arguments (quantity and volume) with equivalent
semantics.
-
trade amountasQuantity: run the order by instrument amount -
trade amountasVolume: run the order by settlement notional -
Pricepresent: treat it as the worst execution price allowed -
Priceabsent: treat the order as market-price execution
This means:
- If a
Priceis provided, the engine must evaluate risk using that price as the worst possible price for the order. - It does not matter whether the order is expressed as quantity-based or
volume-based
trade_amount— wherever a price is required for risk evaluation, the provided price must be treated as the worst-case price. - If
Priceis not provided, the engine must obtain the current market price to evaluate the risk. - If a market price cannot be obtained, the risk check must fail with an error indicating insufficient data to evaluate risk.
| Property | Value |
|---|---|
| Minimum | 1x |
| Maximum | 3000x |
| Step | 0.1x |
Rust behavior:
- Checked arithmetic returns
Result<_, openpit::param::Error> - Rounded constructors accept an explicit
RoundingStrategy -
Price::calculate_volume(quantity)andQuantity::calculate_volume(price)compute absolute notional as|price| × quantity -
Notional::from_price_quantity(price, quantity)computes position exposure as|price| × quantity -
Notional::margin_required(leverage)computes required margin asnotional / leverageusing exact decimal arithmetic -
Notional::from_volume(v)/Volume::from_notional(n)reinterpret between trade size and position exposure without numeric change
Python behavior:
- All decimal-based param types behave like
decimal.Decimalwith domain-type safety: arithmetic works only between operands of the same type. - Constructor accepts
Decimal,str,int, orfloat. - The
.decimalproperty returns the underlyingdecimal.Decimalfor cross-type computations or standard-library interop. -
str(value)produces the canonical decimal string. - Invalid inputs raise
ValueError. -
ParamKindandRoundingStrategyare exposed as stable string constants.
Rust exposes:
openpit::param::ParamKindopenpit::param::RoundingStrategyopenpit::param::Error
Python exposes:
openpit.param.ParamKindopenpit.param.RoundingStrategy
The Python wrappers do not expose the Rust arithmetic error enum directly.
Go:
asset, err := param.NewAsset("AAPL")
if err != nil {
panic(err)
}
quantity, _ := param.NewQuantityFromString("10.5")
price, _ := param.NewPriceFromString("185")
pnl, _ := param.NewPnlFromString("-12.5")
assert(asset.String() == "AAPL")
assert(quantity.String() == "10.5")
assert(price.String() == "185")
assert(pnl.String() == "-12.5")Python:
import openpit
from decimal import Decimal
# Build validated value objects at the integration boundary.
asset = openpit.param.Asset("AAPL")
quantity = openpit.param.Quantity("10.5")
price = openpit.param.Price(185)
pnl = openpit.param.Pnl(-12.5)
# Domain types with exact decimal semantics.
assert asset == "AAPL"
assert str(quantity) == "10.5"
assert str(price) == "185"
assert str(pnl) == "-12.5"
# The .decimal property provides the underlying Decimal for interop.
assert quantity.decimal == Decimal("10.5")
assert isinstance(price.decimal, Decimal)Rust:
use openpit::param::{Asset, Pnl, Price, Quantity};
// Build validated value objects at the integration boundary.
let asset = Asset::new("AAPL").expect("asset code must be valid");
let quantity = Quantity::from_str("10.5").expect("quantity must be valid");
let price = Price::from_str("185").expect("price must be valid");
let pnl = Pnl::from_str("-12.5").expect("pnl must be valid");
// The wrappers normalize formatting while preserving domain meaning.
assert_eq!(asset.as_ref(), "AAPL");
assert_eq!(quantity.to_string(), "10.5");
assert_eq!(price.to_string(), "185");
assert_eq!(pnl.to_string(), "-12.5");Go:
var side param.Side = param.SideBuy
var positionSide param.PositionSide = param.PositionSideLong
assert(side == param.SideBuy)
assert(positionSide == param.PositionSideLong)Python:
import openpit
# Directional helpers keep side logic explicit instead of comparing raw strings.
side = openpit.param.Side.BUY
position_side = openpit.param.PositionSide.LONG
assert side.opposite().value == "sell"
assert side.sign() == 1
assert position_side.opposite().value == "short"Rust:
use openpit::param::{PositionSide, Side};
// Directional helpers keep side logic explicit instead of comparing raw strings.
assert_eq!(Side::Buy.opposite(), Side::Sell);
assert_eq!(Side::Sell.sign(), -1);
assert_eq!(PositionSide::Long.opposite(), PositionSide::Short);Go:
fromMultiplier, _ := param.NewLeverage("100")
fromFloat, _ := param.NewLeverage("100.5")
assert(string(fromMultiplier) == "100.000000000000000000")
assert(string(fromFloat) == "100.500000000000000000")Python:
import openpit
# Leverage is a plain multiplier with direct int/float constructors.
from_multiplier = openpit.param.Leverage(100)
from_float = openpit.param.Leverage(100.5)
# Both constructors end up with the same strongly typed leverage wrapper.
assert from_multiplier.value == 100.0
assert from_float.value == 100.5Rust:
use openpit::param::Leverage;
// Pick the constructor that matches the upstream representation you receive.
let from_multiplier = Leverage::from_u16(100).expect("valid leverage");
let from_float = Leverage::from_f64(100.5).expect("valid leverage");
// Both constructors end up with the same strongly typed leverage wrapper.
assert_eq!(from_multiplier.value(), 100.0);
assert_eq!(from_float.value(), 100.5);- Policies: Value types used by built-in and custom policies
- Architecture: Public integration model