Skip to content

Account Blocking

Eugene Palchukovsky edited this page Jun 8, 2026 · 1 revision

Account Blocking

The accounts handle exposed by the engine carries an admin API for blocking and unblocking accounts and account groups from outside any policy callback. This is distinct from the in-policy kill-switch facility (see Policies - Account Blocking by Engine), which triggers a block automatically when a policy returns a scope = account reject or when apply execution report emits an AccountBlock value.

The admin API is reached through engine.accounts(). The same handle also owns the account group membership registry.

What Gets Blocked

An accounts block gates pre-trade order evaluation only. The engine short-circuits the entire policy chain for every incoming order on the blocked account - no policy runs, and the caller receives an AccountBlocked reject immediately. Account adjustments (non-trade operations on balances and positions) continue to work regardless of block state; the block is strictly a pre-trade signal.

By-Account Blocking

block(account, reason) adds the account to the engine's blocked set. unblock(account) removes it - clearing the block regardless of its origin: it lifts both an admin block set through this API and a kill-switch block recorded by the engine from a policy (for example a PnL limit). If the account is already blocked, calling block again is a no-op - the first reason is kept. Use replace block reason to change the reason of an existing block.

By-Group Blocking (Live Predicate)

block group(group, reason) installs a group-level block. The engine evaluates group membership live on every pre-trade request: any account that is currently a member of a blocked group is rejected, including accounts that join the group after the block was set. Conversely, an account that leaves a blocked group is no longer group-blocked.

unblock group(group) removes the group-level block.

The default account group cannot be passed to block group, unblock group, or replace group block reason - these calls return an error for the reserved default.

Reason

The reason is an operator-supplied free-text cause string. It may be empty; the SDK does not enforce non-emptiness. The reason is replayed in the AccountBlocked reject that the engine returns to the caller on every blocked pre-trade attempt. Enforcing a non-empty reason for operator accountability is the caller's responsibility.

Examples

The examples build an engine, block account 99224416 with a reason, unblock it, and show a one-line group block/unblock.

Go
engine, err := openpit.NewEngineBuilder().
 FullSync().
 Builtin(policies.BuildOrderValidation()).
 Build()
if err != nil {
 log.Fatal(err)
}
defer engine.Stop()

accounts := engine.Accounts()

// Block account 99224416 - all subsequent pre-trade orders are rejected.
accounts.Block(param.NewAccountIDFromUint64(99224416), "compliance hold")

// Unblock account 99224416 - pre-trade orders are allowed again.
accounts.Unblock(param.NewAccountIDFromUint64(99224416))

// Block every current and future member of a group in one call.
desk, err := param.NewAccountGroupIDFromUint32(7)
if err != nil {
 log.Fatal(err)
}
if err := accounts.BlockGroup(desk, "desk suspended"); err != nil {
 log.Fatal(err)
}
if err := accounts.UnblockGroup(desk); err != nil {
 log.Fatal(err)
}
Python
engine = (
    openpit.Engine.builder()
    .no_sync()
    .builtin(openpit.pretrade.policies.build_order_validation())
    .build()
)

accounts = engine.accounts()

# Block account 99224416 - all subsequent pre-trade orders are rejected.
accounts.block(openpit.param.AccountId.from_int(99224416), "compliance hold")

# Unblock account 99224416 - pre-trade orders are allowed again.
accounts.unblock(openpit.param.AccountId.from_int(99224416))

# Block every current and future member of a group in one call.
desk = openpit.param.AccountGroupId.from_int(7)
accounts.block_group(desk, "desk suspended")
accounts.unblock_group(desk)
Rust
use openpit::param::{AccountGroupId, AccountId};
use openpit::pretrade::policies::OrderValidationPolicy;
use openpit::{Engine, OrderOperation};

let engine: openpit::LocalEngine<OrderOperation> = Engine::builder()
    .no_sync()
    .pre_trade(OrderValidationPolicy::new())
    .build()?;

let accounts = engine.accounts();

// Block account 99224416 - all subsequent pre-trade orders are rejected.
accounts.block(AccountId::from_u64(99224416), "compliance hold".to_string());

// Unblock account 99224416 - pre-trade orders are allowed again.
accounts.unblock(AccountId::from_u64(99224416));

// Block every current and future member of a group in one call.
let desk = AccountGroupId::from_u32(7)?;
accounts.block_group(desk, "desk suspended".to_string())?;
accounts.unblock_group(desk)?;

Related Pages

Clone this wiki locally