Skip to main content

TP/SL Updates Dataset

Updated on
Jun 10, 2026

Overview

The StreamTpslUpdates stream delivers the lifecycle of trigger and take-profit/stop-loss orders as ADD and REMOVE diffs. Trigger orders do not appear in the regular order book streams until they trigger. This stream is the way to observe resting TP/SL orders directly. Use it for trigger-order heatmaps, liquidation and stop monitoring, frontend overlays, and alerting around resting TP/SL orders.

gRPC Service: OrderBookStreaming
gRPC Method: StreamTpslUpdates
Update Model: Snapshot of currently-open trigger orders on subscribe, then add/remove diffs per block

How It Works

  1. On subscribe: The first message has snapshot: true and contains all currently-open trigger orders as TPSL_DIFF_TYPE_ADD diffs
  2. Per block thereafter: Each TpslUpdatesUpdate contains ADD diffs for newly placed trigger orders and REMOVE diffs for trigger orders that left the resting set. Removes carry a reason (e.g., "reduceOnlyCanceled") mirroring node order statuses
  3. Maintain a local map of open trigger orders keyed by oid if you need the current resting set

Trigger orders are perpetuals-only, so this stream covers perp coins. An empty coins list subscribes to all perp coins.

Data Structure

Each TpslUpdatesUpdate message contains the trigger-order diffs for one block:

{
"time": 1781109188721,
"height": 586405650,
"diffs": [
{ "diff_type": "TPSL_DIFF_TYPE_ADD", "oid": 54764664388, "coin": "ETH",
"user": "0xA5cace4Bd730bAC2E814CB50c4F3A58DDBA017BF", "side": "B",
"trigger_px": "1702.1", "limit_px": "1872.4", "sz": "0.0294",
"trigger_condition": "Price above 1702.1", "order_type": "Stop Market",
"reduce_only": true, "timestamp": 1781109188721 }
]
}

Request Parameters

FieldTypeRequiredDescription
coinsrepeated stringNoList of perp symbols to subscribe to (e.g., "BTC", "ETH"). Empty means all perp coins

Coin Naming

Trigger orders exist for perpetuals only, so the coins parameter accepts perp names: human-readable symbols like "BTC", "ETH", "HYPE", "SOL". The spot @{index} format does not apply to this stream. An empty list subscribes to all perp coins.

Response Fields

TpslUpdatesUpdate

FieldTypeDescription
timeuint64Block timestamp in milliseconds
heightuint64Block height
snapshotboolTrue when the diffs carry the currently-open trigger orders as a snapshot (sent on subscribe)
diffsTpslOrderDiff[]Trigger-order add/remove diffs for this block

TpslOrderDiff

FieldTypeDescription
diff_typeTpslDiffTypeTPSL_DIFF_TYPE_ADD (trigger order placed) or TPSL_DIFF_TYPE_REMOVE (trigger order left the resting set)
oiduint64Unique order ID
coinstringPerp symbol (e.g., "BTC", "ETH")
userstringEthereum address of the order owner
sidestring"A" (Ask/Sell) or "B" (Bid/Buy)
trigger_pxstringTrigger price as a decimal string
limit_pxstringLimit price as a decimal string (for market trigger orders, the execution limit, which may be offset from trigger_px by a slippage allowance)
szstringOrder size as a decimal string. "0.0" for position TP/SL orders, which are sized by the position
trigger_conditionstringHuman-readable trigger condition (e.g., "Price above 1778")
order_typestringTrigger order type (e.g., "Stop Market", "Stop Limit", "Take Profit Market", "Take Profit Limit")
is_position_tpslboolWhether the order is a position take-profit/stop-loss (sized by the position; sz is "0.0")
reduce_onlyboolWhether the order is reduce-only
timestampuint64Order creation time in milliseconds
reasonstringRemoval reason, present on REMOVE diffs (e.g., "reduceOnlyCanceled"). Mirrors node order statuses

Proto Definition

StreamTpslUpdates is defined in orderbook.proto:

service OrderBookStreaming {
rpc StreamTpslUpdates (TpslUpdatesRequest) returns (stream TpslUpdatesUpdate);
}

message TpslUpdatesRequest {
repeated string coins = 1;
}

enum TpslDiffType {
TPSL_DIFF_TYPE_UNSPECIFIED = 0;
TPSL_DIFF_TYPE_ADD = 1;
TPSL_DIFF_TYPE_REMOVE = 2;
}

message TpslUpdatesUpdate {
uint64 time = 1;
uint64 height = 2;
repeated TpslOrderDiff diffs = 3;
bool snapshot = 4;
}

message TpslOrderDiff {
TpslDiffType diff_type = 1;
uint64 oid = 2;
string coin = 3;
string user = 4;
string side = 5;
string trigger_px = 6;
string limit_px = 7;
string sz = 8;
string trigger_condition = 9;
string order_type = 10;
bool is_position_tpsl = 11;
bool reduce_only = 12;
uint64 timestamp = 13;
string reason = 14;
}

Example Updates

Initial Snapshot (first message, truncated)

The first message has snapshot: true and contains all currently-open trigger orders as ADD diffs:

{
"time": 1781109147521,
"height": 586405394,
"snapshot": true,
"diffs": [
{ "diff_type": "TPSL_DIFF_TYPE_ADD", "oid": 54678088397, "coin": "ETH",
"user": "0x2308ccA96D9Ddde6F9A37D447C87d6B6b267E307", "side": "A",
"trigger_px": "1778.0", "limit_px": "1778.0", "sz": "0.0297",
"trigger_condition": "Price above 1778", "order_type": "Take Profit Market",
"reduce_only": true, "timestamp": 1780996670847 },
{ "diff_type": "TPSL_DIFF_TYPE_ADD", "oid": 54694008956, "coin": "BTC",
"user": "0xB996742Cc1BA8E8A949021dd609f7b45Ac032CC1", "side": "A",
"trigger_px": "60687.0", "limit_px": "60596.0", "sz": "0.00018",
"trigger_condition": "Price below 60687", "order_type": "Stop Limit",
"reduce_only": true, "timestamp": 1781017693515 }
]
}
Position TP/SL Order

Position TP/SL orders carry sz: "0.0" because they are sized by the position at trigger time:

{ "diff_type": "TPSL_DIFF_TYPE_ADD", "oid": 54629542173, "coin": "BTC",
"user": "0x0F15d3Ecc22BE9Ab1C1be2A0a265bfb715af3Ccc", "side": "B",
"trigger_px": "79089.0", "limit_px": "79089.0", "sz": "0.0",
"trigger_condition": "Price above 79089", "order_type": "Stop Market",
"is_position_tpsl": true, "reduce_only": true, "timestamp": 1780928051012 }
Live Add
{
"time": 1781109188721,
"height": 586405650,
"diffs": [
{ "diff_type": "TPSL_DIFF_TYPE_ADD", "oid": 54764664388, "coin": "ETH",
"user": "0xA5cace4Bd730bAC2E814CB50c4F3A58DDBA017BF", "side": "B",
"trigger_px": "1702.1", "limit_px": "1872.4", "sz": "0.0294",
"trigger_condition": "Price above 1702.1", "order_type": "Stop Market",
"reduce_only": true, "timestamp": 1781109188721 }
]
}
Live Remove (with reason)
{
"time": 1781109151770,
"height": 586405419,
"diffs": [
{ "diff_type": "TPSL_DIFF_TYPE_REMOVE", "oid": 54764554453, "coin": "BTC",
"user": "0x4f62EFb29bb38a975C1e54cb39aD3aA4E8777CF4", "side": "A",
"trigger_px": "61968.0", "limit_px": "61968.0", "sz": "0.00019",
"trigger_condition": "Price below 61968", "order_type": "Stop Market",
"reduce_only": true, "timestamp": 1781109080552, "reason": "reduceOnlyCanceled" }
]
}

API Usage

gRPC Streaming
// Specific perp coins
const request = {
coins: ['ETH', 'BTC']
};

// All perp coins
const allCoinsRequest = {
coins: []
};

gRPC Only

StreamTpslUpdates is only available via the gRPC Streaming API (OrderBookStreaming service). It is not available through JSON-RPC or WebSocket.

Important Notes


  • Trigger orders are not in the book streams: Resting TP/SL orders do not appear in StreamL2Book/StreamL4Book until they trigger and convert into regular orders. This stream is the direct view of the resting trigger set
  • Snapshot on subscribe and reconnect: The first message carries all currently-open trigger orders as ADD diffs, so reconnects rebuild state automatically
  • Position TP/SL sizing: Orders with is_position_tpsl: true carry sz: "0.0", as they are sized by the position rather than a fixed size
  • reason on removes: Remove diffs include a reason string mirroring node order statuses (e.g., "reduceOnlyCanceled"), useful for distinguishing cancels from triggers
  • Perp coins only: Trigger orders exist for perpetuals; an empty coins list means all perp coins
  • zstd compression recommended: Enable zstd compression on your gRPC channel to reduce bandwidth, especially when streaming all perp coins

  • StreamL4BookUpdates - Typed per-order book diffs for regular resting orders
  • Orders - Order lifecycle events (open, filled, canceled, etc.)
  • Events - Balance changes, transfers, liquidations, and funding payments
Share this doc