Order Types
Senticore is designed for professional order handling across spot, binary options, and prediction markets.
Every order type below has dedicated behavior test coverage and is included in continuous integration coverage gating. Randomized sequence fuzzing across supported order types runs regularly, asserting deterministic state across independent engine instances.
Time-in-force
| Type | Behavior |
|---|---|
| GTC | Rests on the book until filled, cancelled, or expired |
| IOC | Fills immediately against available liquidity and cancels the remainder |
| FOK | Fills the entire quantity immediately or rejects |
| Post-only | Rests as maker liquidity; rejects if it would cross the spread |
Modifiers
| Modifier | Behavior |
|---|---|
is_market | Market order; takes available liquidity |
reduce_only | Outcome (YES/NO) markets only: can only reduce an existing position. Rejected on spot markets (reduce_only_invalid_side) |
stp_mode | Self-trade prevention behavior |
expires_at | Auto-cancel timestamp for eligible orders |
Self-trade prevention
The engine default is cancel_taker. An account or credential default
overrides the engine default, and an explicit per-order stp_mode overrides
both.
stp_mode | Behavior on an otherwise executable self-cross |
|---|---|
cancel_taker | Preserve the resting maker; cancel the incoming remainder |
cancel_maker | Cancel the resting self-owned maker and continue matching |
reject | Reject the incoming action without changing either order |
skip_self | Skip self-owned makers and continue to external liquidity |
Use the exact lowercase values above on JSON and BSL. FIX tag 7928 and FIXP
use the documented numeric mapping. An unsupported value returns the stable
invalid_stp_mode cause and the allowed values.
Post-only is evaluated before STP. A crossing post-only order is rejected with
post_only_would_cross even when the maker belongs to the same account and the
selected STP mode would normally skip or cancel that maker. This preserves the
invariant that post-only never removes liquidity.
Conditional orders
Conditional orders trigger child orders based on market conditions.
The TypeScript SDK high-level local-signing helpers currently cover
SpotPlaceOrder, OutcomePlaceOrder, Cancel, AmendOrder,
SpotQuoteReplace, and QuoteReplace. Advanced algo and conditional actions
are available as raw signed HTTP/BSL actions where enabled; construct and sign
the raw action payload shown in Raw actions
instead of calling non-existent sdk.placeAlgoOrder or
sdk.placeConditionalOrder helpers.
Stop loss
{
"PlaceConditionalOrder": {
"market": 1,
"book": "YES",
"side": "Ask",
"qty": 100000,
"limit_price": 600000,
"trigger_price": 610000,
"trigger_direction": "at_or_below",
"conditional_kind": "stop_loss",
"reduce_only": true,
"signed_trigger_order": {
"payload": { "...": "pre-signed child order payload" },
"signature": { "scheme": "EcdsaSecp256k1", "bytes": [1, 2, 3] }
}
}
}
| Direction | Use case |
|---|---|
at_or_below | Sell-side stop for downside protection |
at_or_above | Buy-side stop or short-position protection |
Take profit
{
"PlaceConditionalOrder": {
"market": 1,
"book": "YES",
"side": "Ask",
"qty": 100000,
"limit_price": 795000,
"trigger_price": 800000,
"trigger_direction": "at_or_above",
"conditional_kind": "take_profit",
"reduce_only": true,
"signed_trigger_order": {
"payload": { "...": "pre-signed child order payload" },
"signature": { "scheme": "EcdsaSecp256k1", "bytes": [1, 2, 3] }
}
}
}
OCO
One-cancels-other links a take-profit and stop-loss path. Submit the first
conditional order, then submit the second with linked_conditional_id set to
the returned conditional id. When one triggers, the linked order is cancelled.
Algorithmic orders
Algorithmic orders execute over time according to a strategy.
For spot algo orders, omit book (or send null) and use the spot market id;
YES/NO is outcome-market routing only. Conditional orders in the current raw
schema remain outcome-book based and must not be presented as generic spot
conditional orders.
Iceberg
{
"PlaceAlgoOrder": {
"market": 1,
"book": "YES",
"side": "Bid",
"total_qty": 1000000,
"limit_price": 510000,
"strategy": {
"kind": "iceberg",
"display_qty": 100000
}
}
}
Behavior:
- Only the display quantity is visible at a time.
- A new slice posts as the visible slice fills.
- Cancelling the parent releases remaining reserved collateral.
TWAP
{
"PlaceAlgoOrder": {
"market": 1,
"book": "YES",
"side": "Bid",
"total_qty": 1000000,
"limit_price": 510000,
"strategy": {
"kind": "twap",
"slice_qty": 100000,
"interval_ms": 60000,
"start_at": 1781190000000
}
}
}
Behavior:
- Slices are submitted on a fixed interval.
- The last slice is capped to remaining quantity.
- A stale or blocked child order prevents uncontrolled order spam.
VWAP
{
"PlaceAlgoOrder": {
"market": 1,
"book": "YES",
"side": "Bid",
"total_qty": 1000000,
"limit_price": 510000,
"strategy": {
"kind": "vwap",
"participation_bps": 1000,
"min_slice_qty": 100000
}
}
}
Behavior:
- Child size follows recent market volume.
participationBpscontrols the target share of market volume.- Execution pauses when observed volume is zero.
Validation rules
| Rule | Behavior |
|---|---|
| Price tick | Price must align to the market tick size |
| Lot size | Quantity must align to lot size |
| Max quantity | Per-market cap (maxOrderQtyMicro on the market item, where set) is enforced |
| Open order cap | Per-account cap is enforced |
| Book depth cap | Prevents unbounded price-level growth |
| Minimum notional | Rejects dust orders |
| Price range (YES/NO books) | Price must be greater than zero and at most 1000000 (1.000 USDC) on every binary and prediction market; see Markets |
| Market lifecycle | New orders are accepted only while the market status is open and the action ts is before expiryTsMs |
Tick size, lot size, native asset decimals, and minimum notional are
market-definition data. Resolve them from
GET /api/v1/public/exchange-info or GET /api/v1/public/markets; do not
copy representative BTC/ETH/SOL values into an order client. See
Markets for the
live per-market values.
A BSL compact request is checked in two stages, and they fail differently:
- Ingress checks cover the whole HTTP request. Shape, signature, timestamp
skew, the single-account rule, the market lifecycle and expiry, the nonce
window, rate limits and the ingress risk pre-check run before any action is
sequenced. If one action fails, the whole request is rejected (
ok: false,acceptedActions: 0,seqs: [], reason inerror) and none of its actions runs. - After admission, each action is applied on its own. An action that fails
in the engine (price above the outcome cap, tick/lot misalignment, quantity
above
maxOrderQtyMicro, post-only cross, insufficient USDC, base asset or YES/NO shares) is dropped with receiptstatus: dropped,applied: falseand adetailtext. Other actions in the same request are not affected.
A QuoteReplace / SpotQuoteReplace is one action, however many legs it
has. If any leg fails, the whole action is rolled back and every one of its
sequence numbers shows dropped with the same detail, so the bids and asks
quoted in it do not rest either. Size asks below your free inventory, keep
every leg inside the market rules, and put bids and asks in separate actions
when inventory is uncertain. See
Cancel-replace failure behavior.
Common rejection reasons
| Error | Meaning |
|---|---|
post_only_requires_passive_limit_order | Post-only order is marketable or not a passive limit |
post_only_would_cross | Post-only order would cross the spread |
insufficient_balance | Account lacks free balance for the order plus fee buffer |
book_depth_exceeded | Order book depth cap reached |
price_level_order_cap_exceeded | Per-price-level order cap reached |
reduce_only_qty_exceeds_position | Reduce-only order would increase exposure |
reduce_only_invalid_side | Reduce-only used on the wrong side or on a spot market |
InsufficientShares | Ask on a YES/NO book without enough free shares; mint a complete set first (Split, 1 USDC → 1 YES + 1 NO). On a spot market it means an outcome-market envelope was sent by mistake |
price above binary cap: PriceMicros(N) | YES/NO limit price above 1000000 (1.000 USDC). Applies to binary and prediction markets; 1000000 itself is accepted. No stable code assigned yet: machine-mapped as engine_rejected / ENGINE_REJECTED. Not retriable; clamp the price |
market N lifecycle=S is not accepting new orders | Market status is not open (for example halted, closed, resolved_no). No stable code assigned yet. Stop quoting that market and re-read the catalog |
market N expired for trading at T | Action ts is at or after the market's expiryTsMs, although status may still read open. No stable code assigned yet. Stop quoting that market |
TRADING_HALTED | Venue-wide halt ("Trading is halted. Wait for trading to resume before retrying."); poll GET /api/v1/status (tradingHalted, expectedReopenMs) instead of retrying blindly |