Orders and positions
Inspect execution state, submit orders and closes, and distinguish acceptance from fills.
A signal expresses what the strategy wants to do. Orders, positions, and trades describe the execution state it must work with. Read that state before acting and inspect the outcome afterward.
For operation-by-operation behavior and simulator/broker differences, read the full Orders & Positions guides.
Inspect before submitting
The quickstart awaits context.getOrders() and context.getPositions(). Because getOrders is optional in the SJS contract, it explicitly waits when the capability is unavailable rather than assuming the order list is empty.
The example does not trade while any returned order exists. It also waits when more than one position is returned, leaves short positions alone, avoids adding to an existing long, and avoids closing while flat. These rules assume a single-instrument session and deliberately make no account-wide allocation decisions.
An order check is a snapshot, not an atomic lock across independent strategies. If several strategies can trade the same instrument/account, their coordination needs more than this local guard.
Request an entry
The quickstart uses the session API in this form:
const result = await context.placeOrder({
id: `crossover-entry-${frame}`,
instrument: context.instrument,
action: "BUY",
quantity: 1,
type: "MARKET",
}, {
source: "sjs",
metadata: { strategy: "crossover-tutorial", signal },
});This is an excerpt: context, frame, and signal come from the surrounding strategy. The quickstart supplies them.
Keep the full configured instrument object. A display symbol alone may not identify the exchange or futures contract. The order ID helps identify this attempt; do not assume an arbitrary ID provides durable broker-wide idempotency.
The editor contract also describes LIMIT, STOP, and STOP_LIMIT types and limitPrice/stopPrice fields. Their supported combinations and execution semantics depend on the runtime and broker. This tutorial uses only market requests.
Request an exit
Use await context.closePositions(position, { source: "sjs", metadata }) with a real position obtained from the session. The API name is plural, but this call takes one position object. It requests a close; it does not mutate your position snapshot into a filled trade.
In the shared simulated path, closing finds the matching position, applies execution checks, removes matching existing orders, and delegates to order placement. That delegated place call can apply another gate. Broker-native close implementations can differ.
The quickstart waits when any order is pending, including during an EXIT signal, so it does not demonstrate cancel-and-replace behavior. Decide that behavior explicitly before using the pattern for time-critical exits.
Interpret the result
For the tutorial's place/close calls, results other than false, undefined, and null are recorded as accepted. The shared simulated close path itself uses this convention for its delegated placement result.
| Observation | What it establishes |
|---|---|
| Signal generated | The input condition was met |
| Request attempted | The strategy called an execution method |
| API result accepted | The method reported a usable result under this convention |
| Order visible | The runtime reports an order, potentially still pending |
| Position/trade updated | Execution state reflects the resulting outcome |
Different methods can have different return contracts. Do not apply this acceptance rule blindly to a cancellation method that returns void.
Automation and optional L3
Requests use source: "sjs" so they retain their strategy provenance. Automation controls can reject them. If an enabled L3 intent hook is configured, it can also reject ordinary SJS requests. Do not label SJS actions manual or l3 to bypass those controls.
Continue with Working with L3, or use Debugging to trace a missing fill.