Skip to content
Back to App

Orders

The Order endpoints let you place new trades, query existing orders, modify pending orders, and cancel orders that have not yet been filled. These endpoints are at the core of every trading strategy.

Order types

TestMax supports four order types, matching the TopStep ProjectX API:

ValueTypeDescriptionRequired price fields
1LimitExecutes at the specified price or betterlimitPrice
2MarketExecutes immediately at the current market priceNone
3Stop LimitBecomes a limit order when the stop price is reachedstopPrice and limitPrice
4StopBecomes a market order when the stop price is reachedstopPrice

Order sides

ValueSideDescription
0BuyBuy to open a long position or close a short position
1SellSell to open a short position or close a long position

POST Order/place

Place a new order. This is the primary endpoint for entering and exiting trades.

URL: POST /api/topstep-sim/Order/place

Authentication: Bearer token required.

Request body

{
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"type": 2,
"side": 0,
"size": 1,
"limitPrice": null,
"stopPrice": null
}
FieldTypeRequiredDescription
accountIdnumberYesAccount ID from Account/search
contractIdstringYesContract ID from Contract/search
typenumberYesOrder type: 1 = Limit, 2 = Market, 3 = StopLimit, 4 = Stop
sidenumberYes0 = Buy, 1 = Sell
sizenumberYesNumber of contracts to trade (must be > 0)
limitPricenumber or nullConditionalRequired for Limit (1) and StopLimit (3) orders
stopPricenumber or nullConditionalRequired for Stop (4) and StopLimit (3) orders

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"orderId": "ord_abc123",
"orderStatus": 2
}
FieldTypeDescription
orderIdstringUnique identifier for the created order
orderStatusnumberCurrent order status: 1 = Partial, 2 = Filled, 3 = Canceled, 6 = Pending

Examples

# Buy 1 contract at market price
result = api("Order/place", {
"accountId": ACCOUNT_ID,
"contractId": CONTRACT_ID,
"type": 2, # Market
"side": 0, # Buy
"size": 1
})
if result["success"]:
print(f"Order filled: {result['orderId']}")

Error responses

ScenarioerrorMessage
Missing limitPrice on limit order"limitPrice is required for Limit orders"
Missing stopPrice on stop order"stopPrice is required for Stop orders"
Invalid accountId"Account not found"
Invalid contractId"Contract not found"
Size is 0 or negative"Size must be greater than 0"

POST Order/search

Search all orders for an account, including filled, pending, and canceled orders.

URL: POST /api/topstep-sim/Order/search

Authentication: Bearer token required.

Request body

{
"accountId": 12345
}
FieldTypeRequiredDescription
accountIdnumberYesAccount ID

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"orders": [
{
"id": "ord_abc123",
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"type": 2,
"side": 0,
"size": 1,
"limitPrice": null,
"stopPrice": null,
"status": 2,
"fillPrice": 21503.25,
"filledSize": 1,
"createdAt": "2025-01-15T14:30:05Z"
}
]
}
FieldTypeDescription
ordersarrayList of all order objects
orders[].idstringOrder ID
orders[].accountIdnumberAccount ID
orders[].contractIdstringContract ID
orders[].typenumberOrder type (1=Limit, 2=Market, 3=StopLimit, 4=Stop)
orders[].sidenumberOrder side (0=Buy, 1=Sell)
orders[].sizenumberRequested order size
orders[].limitPricenumber or nullLimit price, if set
orders[].stopPricenumber or nullStop price, if set
orders[].statusnumberOrder status (1=Partial, 2=Filled, 3=Canceled, 6=Pending)
orders[].fillPricenumber or nullAverage fill price, if filled
orders[].filledSizenumberNumber of contracts filled so far
orders[].createdAtstringISO 8601 timestamp of when the order was created

Example

result = api("Order/search", {"accountId": ACCOUNT_ID})
if result["success"]:
for order in result.get("orders", []):
status_map = {1: "Partial", 2: "Filled", 3: "Canceled", 6: "Pending"}
side_str = "BUY" if order["side"] == 0 else "SELL"
status_str = status_map.get(order["status"], "Unknown")
print(f"{side_str} {order['size']} — Status: {status_str}")

POST Order/searchOpen

Get only open/pending orders — orders that have not yet been fully filled or canceled.

URL: POST /api/topstep-sim/Order/searchOpen

Authentication: Bearer token required.

Request body

{
"accountId": 12345
}
FieldTypeRequiredDescription
accountIdnumberYesAccount ID

Response

Same format as Order/search, but only includes orders with status of 6 (Pending) or 1 (Partial).

Example

# Check for unfilled limit orders
result = api("Order/searchOpen", {"accountId": ACCOUNT_ID})
open_orders = result.get("orders", [])
print(f"{len(open_orders)} open orders")
# Cancel all open orders before placing new ones
for order in open_orders:
api("Order/cancel", {"orderId": order["id"]})

POST Order/cancel

Cancel a pending order. Only works on orders that have not yet been fully filled.

URL: POST /api/topstep-sim/Order/cancel

Authentication: Bearer token required.

Request body

{
"orderId": "ord_abc123"
}
FieldTypeRequiredDescription
orderIdstringYesThe ID of the order to cancel

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null
}

Example

# Cancel a specific stop-loss order
result = api("Order/cancel", {"orderId": stop_order_id})
if result["success"]:
print(f"Order {stop_order_id} canceled")
else:
print(f"Cancel failed: {result['errorMessage']}")

Error responses

ScenarioerrorMessage
Order already filled"Order is already filled"
Order already canceled"Order is already canceled"
Order not found"Order not found"

POST Order/modify

Modify a pending order’s size, limit price, or stop price. Only works on orders that have not yet been fully filled.

URL: POST /api/topstep-sim/Order/modify

Authentication: Bearer token required.

Request body

{
"orderId": "ord_abc123",
"size": 2,
"limitPrice": 21510.00,
"stopPrice": null
}
FieldTypeRequiredDescription
orderIdstringYesThe ID of the order to modify
sizenumber or nullNoNew order size. Pass null to keep unchanged.
limitPricenumber or nullNoNew limit price. Pass null to keep unchanged.
stopPricenumber or nullNoNew stop price. Pass null to keep unchanged.

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null
}

Example

# Move a stop-loss order to a new price (trail the stop)
result = api("Order/modify", {
"orderId": stop_order_id,
"stopPrice": 21495.00 # Move stop up to lock in profit
})
if result["success"]:
print("Stop moved to 21495.00")

Common patterns

Bracket order (entry + stop-loss + take-profit)

# 1. Enter with a market buy
entry = api("Order/place", {
"accountId": ACCOUNT_ID,
"contractId": CONTRACT_ID,
"type": 2, "side": 0, "size": 1
})
# 2. Place a stop-loss
stop = api("Order/place", {
"accountId": ACCOUNT_ID,
"contractId": CONTRACT_ID,
"type": 4, # Stop
"side": 1, # Sell to close
"size": 1,
"stopPrice": entry_price - 20 # 20 points risk
})
# 3. Place a take-profit
tp = api("Order/place", {
"accountId": ACCOUNT_ID,
"contractId": CONTRACT_ID,
"type": 1, # Limit
"side": 1, # Sell to close
"size": 1,
"limitPrice": entry_price + 40 # 40 points target (2:1 R:R)
})
stop_id = stop["orderId"]
tp_id = tp["orderId"]
# 4. When one fills, cancel the other (in your main loop)
positions = get_positions(ACCOUNT_ID)
if len(positions) == 0:
# Position was closed — cancel remaining order
api("Order/cancel", {"orderId": stop_id})
api("Order/cancel", {"orderId": tp_id})

Cancel all open orders

result = api("Order/searchOpen", {"accountId": ACCOUNT_ID})
for order in result.get("orders", []):
api("Order/cancel", {"orderId": order["id"]})
print("All open orders canceled")

Trailing stop

# Inside your main loop, after checking bar data:
if position and bar["h"] > highest_high:
highest_high = bar["h"]
new_stop = highest_high - trail_distance
api("Order/modify", {
"orderId": stop_order_id,
"stopPrice": new_stop
})
print(f"[INFO] Trailing stop moved to {new_stop}")