Orders and Executions
What a trigger, schedule, ladder, execution, order, and fill each are, and how one becomes the next.
Pear splits one trade into several objects, and their names overlap enough to be confusing. This page defines each one and shows how they connect. Read it once and the rest of the API section reads straightforwardly.
"Order" means two different things
This is the first thing to get straight, because both meanings appear in the same response.
- An instruction you place — a trigger, a TWAP schedule, or a ladder. It waits for something, then acts. The Managing Open Order and Open Order pages mean this one.
- A venue order Pear sends — one entry in an execution's
ordersarray, one per leg, holding the exchange's own status. It has no endpoint of its own.
When a page says "resting order" or "open order", it means the first. When you see orders inside a response body, it is the second.
The objects
| Object | What it is | Read with |
|---|---|---|
| Trigger | An instruction that fires when a market condition is met. | GET /triggers |
| Schedule | An instruction that fires on a clock, slice by slice. TWAP. | GET /schedules |
| Ladder | A group of triggers spread across a price range. | GET /ladders |
| Execution | One run at the venue. Holds the venue orders it sent. | GET /executions |
| Order | One venue order inside an execution, one per leg. | inside execution.orders |
| Fill | One print the venue reports, with its price and fees. | GET /fills |
| Position | The basket you hold, once fills net out. | GET /positions |
How one becomes the next
A market order has no instruction step: POST /trade/open creates an execution straight away, so there is nothing on GET /triggers to find.
How many executions each produces
This is the part that surprises people.
| You placed | Executions it produces |
|---|---|
| A market order | Exactly one. |
| A trigger | One, when it fires. The trigger is then spent and reports TRIGGERED. |
| A schedule | One per slice. A TWAP over twelve slices produces twelve. |
| A ladder | One per rung that fires, up to levels. |
Because a schedule and a ladder produce many, GET /executions hides their runs by default, so one TWAP does not bury every other action. Add includeSchedule=true or includeTriggers=true to see them. See Execution.
A ladder is made of triggers
A ladder is a parent with one child trigger per rung, spaced evenly across your range and each carrying an equal share of the size. levels sets the rung count, from 2 to 50, and weighting is always EQUAL.
That has three consequences:
- A ladder has no executions of its own. A rung's execution names the trigger, and that trigger carries
ladderIdandladderIndex. - Ladder rungs show up on
GET /triggersalongside your other triggers. Filter them out byladderIdwhen you do not want them. GET /laddersreturns each ladder with its rungs attached, ordered byladderIndex, which is the easier way to read a ladder's progress.
An instruction outlives the wait
Firing does not delete the instruction. A trigger that fired is still readable, now reporting TRIGGERED, with the fills it produced attached. The list endpoints return every state by default, so ask for status=ACTIVE when you want only what is still resting. See Open Order.
Filtering a list by status
status accepts exactly three values, on every list that takes it: ACTIVE, COMPLETED, CANCELLED. They are a query vocabulary, not the object's own statuses, and they do not line up one to one.
| List | Takes status | What COMPLETED selects |
|---|---|---|
GET /triggers | Yes | Triggers reporting TRIGGERED. |
GET /executions | Yes | Executions reporting COMPLETED or FAILED. |
GET /schedules | Yes | Schedules reporting COMPLETED or FAILED. |
GET /ladders | No | — |
Three consequences:
GET /laddershas no status filter. Sendingstatus=ACTIVEthere is silently dropped and you get every ladder, in every state. Filter client-side.status=COMPLETEDincludes failures on executions and on schedules. Read each row's ownstatusbefore you treat it as a success.FAILEDis not selectable. There is nostatus=FAILED. Ask forCOMPLETEDand filter the response.
Statuses at a glance
Each object has its own vocabulary. None of them share a set, so do not reuse a status check across two.
| Object | Statuses |
|---|---|
| Trigger | ACTIVE, TRIGGERED, CANCELLED |
| Schedule | ACTIVE, COMPLETED, FAILED, CANCELLED |
| Ladder | ACTIVE, COMPLETED, CANCELLED |
| Execution | IDLE, ACTIVE, COMPLETED, FAILED, CANCELLED |
| Order | PENDING, PARTIAL, FILLED, CANCELLED, REJECTED |
| Fill | PROVISIONAL, CONFIRMED, RECONCILED |
| Position | OPEN, CLOSED |
intent is a separate vocabulary again, and the three objects that carry it do not share a set either:
| Object | intent values |
|---|---|
| Trigger | OPEN, ADJUST, CLOSE |
| Schedule | OPEN, CLOSE |
| Execution | OPEN, ADJUST, CLOSE, REVERSE |
One trap lives in here: an execution can be FAILED while some of its orders are FILLED, which is how a basket ends up one-sided. See Error Handling.
Cancelling
Cancelling removes what has not happened yet. It never unwinds what has.
| Cancel | Stops | Leaves |
|---|---|---|
| A trigger | The trigger firing. | Nothing; it never ran. |
| A schedule | Its pending slices. | Every slice that already filled, as part of your position. |
| A ladder | Its unfired rungs. | Every rung that already filled. |
So cancelling a half-finished TWAP leaves you holding whatever it built. Read that with GET /positions. See Managing Open Order.
You are not the only thing that cancels. A cancelled trigger or schedule carries a cancelledReason, and only one of its values is you:
cancelledReason | What happened |
|---|---|
USER | You cancelled it. |
POSITION_CLOSED | The position it was attached to closed. |
POSITION_NETTED | The position was netted away against an opposing one. |
POSITION_REVERSED | The position was reversed, so the bracket no longer matches the exposure. |
SYSTEM | Pear cancelled it. |
A close trigger you never touched can therefore turn up CANCELLED. Check the reason before you treat it as user action.
cancelledReason is absent unless the object was cancelled. Schedules carry the same five values.
States before the object is armed
Two objects have an internal state that precedes ACTIVE, and they surface it differently:
- A trigger is created
IDLE, then armed.GET /triggersfiltersIDLEout unconditionally, whateverstatusyou pass, so you never see one. - An execution is created
IDLE, before its orders exist. It can come back onGET /executions, but there is nostatus=IDLEto ask for it. Treat it as "not started yet". - A position is
OPENINGwhile an order is still trying to create exposure. That state never reaches the API. On the wire a position is only everOPENorCLOSED.
Close triggers are triggers too
A take profit or a stop loss is a trigger with intent: "CLOSE". It appears on GET /triggers next to your entry triggers, and produces a closing execution when it fires. Tell them apart with intent.
Two fields need care:
- The position it closes is at
context.position.id, not at a top-levelpositionId. There is no top-levelpositionIdon any trigger. An adjust trigger nests it the same way. - Read
semanticBracketType, notbracketType, for which side it protects.bracketTypeis the crossing encoding the gateway fires on, and it is flipped on a price bracket that watches a short leg, so it does not report what the user asked for.semanticBracketTypedoes. It is absent only where an older client's encoding cannot be recovered; in that case report nothing rather than presentingbracketTypeas intent.
Not on this list: auto-rebalance
Auto-rebalance is a standing config rather than an instruction that fires once. It is ACTIVE or PAUSED, read with GET /rebalance/auto, and its history is at GET /rebalance/{positionId}/events rather than in the execution list. See Auto-Rebalance.
Where each is documented
| To | Go to |
|---|---|
| Place one | Order Type |
| Cancel one | Managing Open Order |
| Read resting instructions | Open Order |
| Read what ran | Execution |
| Read the prints | Fills |
| Read what you hold | Open Position |