openpit

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Pit (Pre-trade Integrity Toolkit) for Go

Read-only mirror. This repository is a mirror of bindings/go/ from the openpitkit/pit monorepo. Do not open pull requests here — contribute to the monorepo instead.

Verify Release Go version Module License

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

For an overview and links to all resources, see the project website openpit.dev. For full project documentation, see the repository README. For conceptual and architectural pages, see the project wiki. For the public Go module source, see go.openpit.dev/openpit.

Versioning Policy (Pre‑1.0)

Until Pit reaches a stable 1.0 release, the project follows a relaxed interpretation of Semantic Versioning.

During this phase:

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

This means that breaking API changes can appear in minor releases before 1.0. Consumers of the library should take this into account when declaring dependencies and consider using version constraints that tolerate API evolution during the pre‑stable phase.

Getting Started

Visit the Go module page and the project wiki for conceptual pages and architecture notes.

Install

go get go.openpit.dev/openpit

Engine

Overview

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

  • engine.StartPreTrade(order) runs start-stage policies; returns (*pretrade.Request, []reject.Reject, error)
  • request.Execute() runs main-stage policies; returns (*pretrade.Reservation, []reject.Reject, error)
  • reservation.Commit() applies reserved state
  • reservation.Close() rolls back any uncommitted reservation automatically
  • engine.ExecutePreTrade(order) is a shortcut that composes both stages
  • engine.ApplyExecutionReport(report) updates post-trade policy state

Start-stage policies stop on the first reject. Main-stage policies aggregate rejects and roll back registered mutations in reverse order when any reject is produced.

Built-in start-stage policies currently include:

  • policies.NewOrderValidation()
  • policies.NewPnlBoundsKillSwitchPolicy(...)
  • policies.NewRateLimitPolicy(...)
  • policies.NewOrderSizeLimitPolicy(...)

The primary integration model is to write project-specific policies against the public Go policy API described in the wiki: Custom Go policies.

There are two types of rejections: a full kill switch for the account and a rejection of only the current request. This is useful in algorithmic trading when automatic order submission must be halted until the situation is analyzed.

Threading

Canonical contract: Threading Contract.

The Go binding follows the same SDK threading contract. Goroutine migration between OS threads during one SDK call is supported, and callbacks invoked by the SDK may run on a different OS thread than the goroutine that initiated the call.

Usage

package main

import (
 "fmt"
 "log"

 "go.openpit.dev/openpit"
 "go.openpit.dev/openpit/model"
 "go.openpit.dev/openpit/param"
 "go.openpit.dev/openpit/pkg/optional"
 "go.openpit.dev/openpit/pretrade/policies"
)

func main() {
 usd, err := param.NewAsset("USD")
 if err != nil {
  log.Fatal(err)
 }

 lowerBound, err := param.NewPnlFromString("-1000")
 if err != nil {
  log.Fatal(err)
 }
 maxQty, err := param.NewQuantityFromString("500")
 if err != nil {
  log.Fatal(err)
 }
 maxNotional, err := param.NewVolumeFromString("100000")
 if err != nil {
  log.Fatal(err)
 }

 // 1. Configure policies.
 pnlPolicy, err := policies.NewPnlBoundsKillSwitchPolicy(
  policies.PnlBoundsBarrier{
   SettlementAsset: usd,
   LowerBound:      optional.Some(lowerBound),
   InitialPnl:      param.PnlZero,
  },
 )
 if err != nil {
  log.Fatal(err)
 }
 defer pnlPolicy.Close()

 sizePolicy, err := policies.NewOrderSizeLimitPolicy(
  policies.OrderSizeLimit{
   SettlementAsset: usd,
   MaxQuantity:     maxQty,
   MaxNotional:     maxNotional,
  },
 )
 if err != nil {
  log.Fatal(err)
 }
 defer sizePolicy.Close()

 // 2. Build the engine (one time at the platform initialization).
 builder, err := openpit.NewEngineBuilder()
 if err != nil {
  log.Fatal(err)
 }
 builder.BuiltinCheckPreTradeStartPolicy(
  policies.NewOrderValidation(),
  pnlPolicy,
  policies.NewRateLimitPolicy(100, 1),
  sizePolicy,
 )
 engine, err := builder.Build()
 if err != nil {
  log.Fatal(err)
 }
 defer engine.Stop()

 // 3. Check an order.
 order := model.NewOrder()
 op := order.EnsureOperationView()
 aapl, err := param.NewAsset("AAPL")
 if err != nil {
  log.Fatal(err)
 }
 op.SetInstrument(param.NewInstrument(aapl, usd))
 op.SetAccountID(param.NewAccountIDFromInt(99224416))
 op.SetSide(param.SideBuy)
 price, _ := param.NewPriceFromString("185")
 qty, _ := param.NewQuantityFromString("100")
 op.SetTradeAmount(param.NewQuantityTradeAmount(qty))
 op.SetPrice(price)

 request, rejects, err := engine.StartPreTrade(order)
 if err != nil {
  log.Fatal(err)
 }
 if rejects != nil {
  for _, r := range rejects {
   fmt.Printf("rejected by %s [%d]: %s (%s)\n", r.Policy, r.Code, r.Reason, r.Details)
  }
  return
 }
 defer request.Close()

 // 4. Quick, lightweight checks were performed during start stage. 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.
 reservation, rejects, err := request.Execute()
 if err != nil {
  log.Fatal(err)
 }
 if rejects != nil {
  for _, r := range rejects {
   fmt.Printf("rejected by %s [%d]: %s (%s)\n", r.Policy, r.Code, r.Reason, r.Details)
  }
  return
 }
 defer reservation.Close()

 // Optional shortcut for the same two-stage flow:
 // reservation, rejects, err := engine.ExecutePreTrade(order)

 // 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.
 reservation.Commit()

 // 7. The order goes to the venue and returns with an execution report.
 report := model.NewExecutionReport()
 reportOp := model.NewExecutionReportOperation()
 reportOp.SetInstrument(param.NewInstrument(aapl, usd))
 reportOp.SetAccountID(param.NewAccountIDFromInt(99224416))
 reportOp.SetSide(param.SideBuy)
 report.SetOperation(reportOp)

 pnl, _ := param.NewPnlFromString("-50")
 fee, _ := param.NewFeeFromString("3.4")
 impact := model.NewExecutionReportFinancialImpact()
 impact.SetPnl(pnl)
 impact.SetFee(fee)
 report.SetFinancialImpact(impact)

 result, err := engine.ApplyExecutionReport(report)
 if err != nil {
  log.Fatal(err)
 }

 // 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.
 if result.KillSwitchTriggered {
  fmt.Println("halt new orders until the blocked state is cleared")
 }
}

Errors

Policy rejects from engine.StartPreTrade() and request.Execute() are returned as the second return value ([]reject.Reject). A non-nil list means the request was rejected; a nil list means the stage passed.

Infrastructure failures and API misuse are returned as the third return value (error):

  • error from engine.StartPreTrade(), request.Execute(), or engine.ApplyExecutionReport() indicates a transport-level or lifecycle failure, not a business reject
  • error from policy constructors such as policies.NewPnlBoundsKillSwitchPolicy() indicates an invalid configuration

Business rejects use stable codes, for example reject.CodeOrderQtyExceedsLimit when an order quantity exceeds the configured limit.

Runtime Delivery

The native runtime library is embedded inside the Go module at build time using Go's embed package. No network download happens at runtime.

On first use, the embedded library is extracted to the user cache directory under a path that includes the SDK version and the GOOS-GOARCH target tuple. Subsequent process starts find the cached file and skip extraction.

  • Target selection uses runtime.GOOS and runtime.GOARCH.
  • Extraction cache path: <user-cache>/pit-go/<version>/<goos>-<goarch>/.

Environment overrides:

  • OPENPIT_RUNTIME_LIBRARY_PATH — use an explicit pre-extracted library path instead of the embedded copy; extraction is skipped entirely.
  • OPENPIT_RUNTIME_CACHE_DIR — override the root directory for extraction instead of the OS user cache directory.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ClientEngine

type ClientEngine[
	Order pretrade.ClientOrder,
	Report pretrade.ClientExecutionReport,
	Adjustment accountadjustment.ClientAccountAdjustment,
] struct {
	// contains filtered or unexported fields
}

ClientEngine runs the standard engine through client-owned order, execution report, and account-adjustment types.

The ordinary Engine API remains the zero-payload fast path. ClientEngine is the opt-in path that allocates a cgo.Handle per submitted client payload so callbacks can receive the original typed value.

Threading: ClientEngine follows the same threading contract as Engine. Payload handles allocated by the SDK (cgo.Handle wrapped around the client value) are released synchronously inside the same call that created them, so callers do not need to extend payload lifetime beyond that call.

func (*ClientEngine[Order, Report, Adjustment]) ApplyAccountAdjustment

func (e *ClientEngine[Order, Report, Adjustment]) ApplyAccountAdjustment(
	accountID param.AccountID,
	adjustments []Adjustment,
) (optional.Option[reject.AccountAdjustmentBatchError], error)

ApplyAccountAdjustment applies client account-adjustment payloads.

Payload handles are released before ApplyAccountAdjustment returns because account-adjustment callbacks are synchronous.

func (*ClientEngine[Order, Report, Adjustment]) ApplyExecutionReport

func (e *ClientEngine[Order, Report, Adjustment]) ApplyExecutionReport(
	report Report,
) (PostTradeResult, error)

ApplyExecutionReport applies a client execution report payload.

The payload handle is released before ApplyExecutionReport returns because report callbacks are synchronous.

func (*ClientEngine[Order, Report, Adjustment]) ExecutePreTrade

func (e *ClientEngine[Order, Report, Adjustment]) ExecutePreTrade(
	order Order,
) (*pretrade.Reservation, []reject.Reject, error)

ExecutePreTrade runs the full pre-trade pipeline with a client order payload.

The payload handle is released before ExecutePreTrade returns because all order callbacks have completed by then.

func (*ClientEngine[Order, Report, Adjustment]) StartPreTrade

func (e *ClientEngine[Order, Report, Adjustment]) StartPreTrade(
	order Order,
) (*ClientRequest, []reject.Reject, error)

StartPreTrade runs the start stage with a client order payload.

On accept, the returned ClientRequest owns the payload handle and releases it when Execute or Close is called. On reject or error, the handle is released before StartPreTrade returns.

func (*ClientEngine[Order, Report, Adjustment]) Stop

func (e *ClientEngine[Order, Report, Adjustment]) Stop()

Stop releases the underlying engine.

type ClientEngineBuilder

type ClientEngineBuilder[
	Order pretrade.ClientOrder,
	Report pretrade.ClientExecutionReport,
	Adjustment accountadjustment.ClientAccountAdjustment,
] struct {
	// contains filtered or unexported fields
}

func NewClientAccountAdjustmentEngineBuilder

func NewClientAccountAdjustmentEngineBuilder[
	Adjustment accountadjustment.ClientAccountAdjustment,
](options ...ClientEngineOption) (
	*ClientEngineBuilder[model.Order, model.ExecutionReport, Adjustment],
	error,
)

NewClientAccountAdjustmentEngineBuilder creates a client builder for custom account-adjustment types while keeping orders and execution reports on the standard SDK model types.

func NewClientEngineBuilder

func NewClientEngineBuilder[
	Order pretrade.ClientOrder,
	Report pretrade.ClientExecutionReport,
	Adjustment accountadjustment.ClientAccountAdjustment,
](options ...ClientEngineOption) (*ClientEngineBuilder[Order, Report, Adjustment], error)

NewClientEngineBuilder creates a builder for strategies that use custom order, execution report, and account-adjustment types.

Policies added to this builder receive client types directly. The builder adapts them to the standard engine policies and keeps payload handles entirely inside the SDK boundary.

func NewClientPreTradeEngineBuilder

func NewClientPreTradeEngineBuilder[
	Order pretrade.ClientOrder,
	Report pretrade.ClientExecutionReport,
](
	options ...ClientEngineOption,
) (*ClientEngineBuilder[Order, Report, model.AccountAdjustment], error)

NewClientPreTradeEngineBuilder creates a client builder for custom order and execution report types while keeping account adjustments on the standard SDK model type.

func (*ClientEngineBuilder[Order, Report, Adjustment]) AccountAdjustmentPolicy

func (b *ClientEngineBuilder[Order, Report, Adjustment]) AccountAdjustmentPolicy(
	policy ...accountadjustment.ClientPolicy[Adjustment],
) *ClientEngineBuilder[Order, Report, Adjustment]

AccountAdjustmentPolicy adds client typed account-adjustment policies.

func (*ClientEngineBuilder[Order, Report, Adjustment]) Build

func (b *ClientEngineBuilder[Order, Report, Adjustment]) Build() (
	*ClientEngine[Order, Report, Adjustment],
	error,
)

Build constructs a ClientEngine and transfers ownership of policies to it.

func (*ClientEngineBuilder[Order, Report, Adjustment]) CheckPreTradeStartPolicy

func (b *ClientEngineBuilder[Order, Report, Adjustment]) CheckPreTradeStartPolicy(
	policy ...pretrade.ClientCheckPreTradeStartPolicy[Order, Report],
) *ClientEngineBuilder[Order, Report, Adjustment]

CheckPreTradeStartPolicy adds client typed start policies.

func (*ClientEngineBuilder[Order, Report, Adjustment]) Close

func (b *ClientEngineBuilder[Order, Report, Adjustment]) Close()

Close releases the underlying builder and any policies it still owns.

func (*ClientEngineBuilder[Order, Report, Adjustment]) PreTradePolicy

func (b *ClientEngineBuilder[Order, Report, Adjustment]) PreTradePolicy(
	policy ...pretrade.ClientPreTradePolicy[Order, Report],
) *ClientEngineBuilder[Order, Report, Adjustment]

PreTradePolicy adds client typed main pre-trade policies.

type ClientEngineOption

type ClientEngineOption func(*clientEngineOptions)

func UnsafeFastClientPayloadCallbacks

func UnsafeFastClientPayloadCallbacks() ClientEngineOption

UnsafeFastClientPayloadCallbacks selects callback adapters that trust every client payload reaching client policies to carry the builder's declared type.

This mode removes safe adapter checks from every callback. A missing payload or a wrong payload type panics.

type ClientRequest

type ClientRequest struct {
	// contains filtered or unexported fields
}

ClientRequest is a deferred pre-trade request that keeps the original client order payload alive until the request is executed or closed.

func (*ClientRequest) Close

func (r *ClientRequest) Close()

Close releases the request and the client order payload.

func (*ClientRequest) Execute

func (r *ClientRequest) Execute() (*pretrade.Reservation, []reject.Reject, error)

Execute runs the deferred pre-trade request and releases the client order payload after callbacks complete.

Execute does not close the underlying request; call Close after Execute just as with a standard pretrade.Request.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

func (*Engine) ApplyAccountAdjustment

func (e *Engine) ApplyAccountAdjustment(
	accountID param.AccountID,
	adjustments []model.AccountAdjustment,
) (optional.Option[reject.AccountAdjustmentBatchError], error)

func (*Engine) ApplyExecutionReport

func (e *Engine) ApplyExecutionReport(report model.ExecutionReport) (PostTradeResult, error)

func (*Engine) ExecutePreTrade

func (e *Engine) ExecutePreTrade(order model.Order) (*pretrade.Reservation, []reject.Reject, error)

ExecutePreTrade runs the full pre-trade pipeline and, on accept, returns a reservation representing the reserved but not yet finalized state.

Return contract:

  • on accept, returns a non-nil *pretrade.Reservation; the caller takes ownership and must resolve it exactly once via CommitAndClose, RollbackAndClose, or Close (which rolls back any pending mutations implicitly);
  • on reject, returns a non-nil []reject.Reject; no Reservation is produced;
  • on transport error, returns a Go error; no Reservation is produced.

func (*Engine) StartPreTrade

func (e *Engine) StartPreTrade(order model.Order) (*pretrade.Request, []reject.Reject, error)

StartPreTrade runs the start stage of the pre-trade pipeline.

Return contract:

  • on accept, returns a non-nil *pretrade.Request; the caller takes ownership and must release it with Request.Close when done (Execute does not close the request — see Request.Execute);
  • on reject, returns a non-nil []reject.Reject; no Request is produced;
  • on transport error, returns a Go error; no Request is produced.

func (*Engine) Stop

func (e *Engine) Stop()

Stop signals the engine to halt internal evaluation, releases policies registered on the engine, and frees the underlying native resources.

After Stop returns, the engine handle is no longer valid for any operation. The engine must no longer be passed to any other method (StartPreTrade, ExecutePreTrade, ApplyExecutionReport, ApplyAccountAdjustment); doing so is undefined behavior.

Idempotency: safe to call more than once; subsequent calls are no-ops.

Outstanding objects previously produced by this engine (pretrade.Request, pretrade.Reservation) remain owned by the caller and must be released independently.

type EngineBuilder

type EngineBuilder struct {
	// contains filtered or unexported fields
}

func NewEngineBuilder

func NewEngineBuilder() (*EngineBuilder, error)

NewEngineBuilder returns a new engine builder. The returned builder must be released by calling either Close or Build after use.

func (*EngineBuilder) AccountAdjustmentPolicy

func (b *EngineBuilder) AccountAdjustmentPolicy(policy ...accountadjustment.Policy) *EngineBuilder

func (*EngineBuilder) Build

func (b *EngineBuilder) Build() (*Engine, error)

Build constructs the engine and releases the builder. The builder is closed on both success and failure, so an explicit Close afterwards is a no-op. On failure, any policies that were accepted by the builder but not transferred to the engine are closed by the builder. On success, ownership of the returned engine passes to the caller, who must release it by calling Stop. Behavior is undefined if Build is called more than once on the same builder.

func (*EngineBuilder) BuiltinCheckPreTradeStartPolicy

func (b *EngineBuilder) BuiltinCheckPreTradeStartPolicy(
	policy ...pretrade.BuiltinPolicy,
) *EngineBuilder

func (*EngineBuilder) CheckPreTradeStartPolicy

func (b *EngineBuilder) CheckPreTradeStartPolicy(
	policy ...pretrade.CheckStartPolicy,
) *EngineBuilder

func (*EngineBuilder) Close

func (b *EngineBuilder) Close()

Close releases the builder and any policies that were handed to it but never transferred to the engine. Safe to call more than once and safe to call after Build; subsequent calls are no-ops.

func (*EngineBuilder) PreTradePolicy

func (b *EngineBuilder) PreTradePolicy(policy ...pretrade.Policy) *EngineBuilder

type PostTradeResult

type PostTradeResult struct {
	KillSwitchTriggered bool
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL