POST Place Order
- NT8
- Tradovate
Place an order NT8
Submits a new market, limit, stop, or other supported order to the selected NT8 account.
Endpoint
POST /v1/api/accounts/{account}/orders/place
Headers
| Name | Value |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <token> |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
account | string | Required | Name of account in NT8 |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
instrument | string | Required | Name of underlying instrument (e.g., "ES 12-25") |
action | string | Required | BUY, SELL |
quantity | int | Required | Contract quantity of new order |
orderType | string | Required | MARKET, LIMIT, STOPMARKET, STOPLIMIT |
timeInForce | string | Required | DAY, GTC |
limitPrice | float | Optional | Limit price when submitting limit order type |
stopPrice | float | Optional | Stop price when submitting stop order type |
ocoId | string | Optional | Create or append to OCO order by ID |
strategy | string | Optional | ATM strategy name if opening with ATM template |
orderId | string | Optional | Custom order ID to assign at placement. If provided, this ID can be used to look up or cancel the order later. |
requireMarketPosition | string | Optional | Comma-separated list of position states that must be true for the order to be accepted: "flat", "long", "short". Example: "flat" blocks the order if a position is already open. "flat,long" allows entry from flat or adding to a long. If the condition is not met, a 400 error is returned and no order is placed. |
maxPositions | int | Optional | Maximum number of distinct non-flat positions allowed on the account. A new instrument position is rejected when the account already has this many open positions; adding to an existing instrument position does not increase the count. |
Code examples
- Python
- JavaScript
- cURL
import requests
token = 'my-secret-token'
url = "https://app.crosstrade.io/v1/api/accounts/Sim101/orders/place"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
data = {
"instrument": "MES 12-25",
"action": "BUY",
"orderType": "MARKET",
"quantity": 1,
"timeInForce": "DAY",
"orderId": "my-strategy-entry-001",
# "limitPrice": 5500
# "stopPrice": 0,
# "ocoId": "abc123",
# "strategy": "MyAtmStrategy"
}
try:
response = requests.post(url, headers=headers, json=data)
print(f"Response Code: {response.status_code}, Response Text: {response.text}")
except Exception as e:
print(f"An error occurred: {e}")
const token = 'my-secret-token';
const url = "https://app.crosstrade.io/v1/api/accounts/Sim101/orders/place";
const data = {
instrument: "MES 12-25",
action: "BUY",
orderType: "MARKET",
quantity: 1,
timeInForce: "DAY",
orderId: "my-strategy-entry-001",
// limitPrice: 5500,
// stopPrice: 0,
// ocoId: "abc123",
// strategy: "MyAtmStrategy"
};
fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
TOKEN="my-secret-token"
curl -X POST "https://app.crosstrade.io/v1/api/accounts/Sim101/orders/place" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"instrument": "MES 12-25",
"action": "BUY",
"orderType": "MARKET",
"quantity": 1,
"timeInForce": "DAY",
"orderId": "my-strategy-entry-001"
}'
Response
- 200
- 400
{
"orderId": "cb1fc8d4e1a84d29ae38fea964aaac8c",
"success": true
}
In this example, cb1fc8d4e1a84d29ae38fea964aaac8c is the NT8-assigned order ID returned by the add-on. The custom ID my-strategy-entry-001 remains stored in NT8 UserData under AutomatedTradingOrderId and can also be used for subsequent order lookups.
{
"error": "Invalid request"
}
Platform nuances
orderId behavior
The optional orderId body field is a caller-supplied reconciliation ID, not the same field as NinjaTrader's live Order.OrderId. If you provide orderId, CrossTrade stores it inside the NT8 order's UserData XML as AutomatedTradingOrderId so the order can still be found later by your original ID.
NT8, the connected broker, or a prop firm connection has ultimate control over the actual order ID. That ID can change over the lifetime of an order, so CrossTrade stores your custom ID separately from the current NT8 order ID instead of trying to overwrite NT8's own identifier.
The orderId returned by a successful place response is the current NT8-assigned order ID at placement time. It may be different from the custom orderId you sent. For later lookup, cancel, change, replace, or lifecycle calls, you can use either the returned NT8 ID or the custom orderId you supplied.
If you are retrying after a timeout, dropped connection, or ambiguous placement result, generate a unique custom orderId for the intended order, send it with the first request, then query by that same ID before sending another placement. Do not assume a separate duplicate-suppression window beyond this ID-based reconciliation path.
WebSocket API
This request can also be made over the WebSocket API. The account path parameter and request body fields are all passed inside args.
{
"action": "rpc",
"id": "my-request",
"api": "PlaceOrder",
"args": {
"account": "Sim101",
"instrument": "ES 09-26",
"action": "Buy",
"orderType": "Market",
"quantity": 1,
"timeInForce": "Gtc",
"orderId": "my-strategy-entry-001"
}
}
Place an order Tradovate
Submits a new order to a linked Tradovate account. No NinjaTrader add-on is involved: the call executes server-side against the Tradovate Web API and runs through the same validation and controls as a Tradovate webhook signal, so field validation, Account Manager locks, and Trade Copier fan-out all apply.
Endpoint
POST /v1/api/tv/accounts/{account}/orders/place
Headers
| Name | Value |
|---|---|
| Content-Type | application/json |
| Authorization | Bearer <token> |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
account | string | Required | Tradovate account name, for example DEMO12345678. |
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
instrument | string | Required | Continuous (ES1!), NT8 (ES 09-26), or Tradovate (ESU6) instrument form. |
action | string | Required | buy or sell. |
qty | int | Required | Contract quantity. |
orderType | string | Required | market, limit, stop, stoplimit, mit, trailingstop, or trailingstoplimit. |
limitPrice | number | Optional | Limit price for an order type that uses one. |
stopPrice | number | Optional | Stop price for an order type that uses one. |
tif | string | Optional | Time in force. |
orderId | string | Optional | Caller-supplied order reference. |
text | string | Optional | Free-form order text. Truncated to 64 characters (Tradovate's limit). |
takeProfit | number | Optional | Absolute target price for a server-side OCO bracket. |
stopLoss | number | Optional | Absolute stop price for a server-side OCO bracket. |
atmTargets | string | Optional | Inline ATM profit-target tiers. |
atmStops | string | Optional | Inline ATM stop tiers. |
atmQtys | string | Optional | Contract quantities for the inline ATM tiers. |
atmTrail | string | Optional | Per-tier trailing-stop toggles. |
atmTrailTrigger | string | Optional | Profit distance in ticks or points that activates trailing tiers. Set with atmTrailOffset. |
atmTrailOffset | string | Optional | Distance in ticks or points the activated stop follows behind price. Set with atmTrailTrigger. |
atmBreakeven | int | Optional | Target tier whose fill moves remaining stops to breakeven. |
atmBreakevenOffset | string | Optional | Breakeven offset for the inline ATM bracket. |
flattenFirst | bool | Optional | Flatten the position and cancel working orders on this instrument before entering. |
requireMarketPosition | string | Optional | Only place the order when the current position matches flat, long, short, or an accepted comma-separated combination. |
maxPositions | int | Optional | Block the entry when this many positions are already open on the account. |
cancelAfter | int | Optional | Cancel an unfilled limit entry after this many minutes. Accepted range: 1 to 180. |
expireTime | string | Optional | ISO-8601 expiry. Required when tif=gtd. |
maxShow | int | Optional | Native iceberg display quantity. |
trailOffset | number | Optional | Native trailing-stop distance. Required for trailing order types. |
pegDifference | number | Optional | Alias of trailOffset. |
syncStrategy | bool | Optional | Enable Tradovate Strategy Sync for this entry command. |
marketPosition | string | Optional | Remote strategy target side: flat, long, or short. |
prevMarketPosition | string | Optional | Remote strategy side before this signal. |
outOfSync | string | Optional | Mismatch policy: wait, flatten, ignore, or resync. |
targetQuantity | int | Optional | Exact signed target quantity for resync. |
strategyExitBlock | bool | Optional | Reject non-opening strategy transitions. |
atmTargets, atmStops, atmQtys, and triggerless atmTrail become a Tradovate-native multibracket. atmTrailTrigger/atmTrailOffset and atmBreakeven are CrossTrade-exclusive beta management. Triggered trails use CrossTrade's own live pricing, never Tradovate entitlement data; target-fill breakeven is driven by broker fill state. The fixed native stop remains active until trail conversion. Managed fields require a Day entry and have a 24-hour watcher lifetime.
Code examples
- Python
- JavaScript
- cURL
import requests
token = 'my-secret-token'
url = "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
data = {
"instrument": "ES1!",
"action": "buy",
"qty": 1,
"orderType": "market",
# "limitPrice": 5000.25,
# "stopPrice": 4995.00,
# "takeProfit": 5020.00,
# "stopLoss": 4990.00
}
try:
response = requests.post(url, headers=headers, json=data)
print(f"Response Code: {response.status_code}, Response Text: {response.text}")
except Exception as e:
print(f"An error occurred: {e}")
const token = 'my-secret-token';
const url = "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place";
const data = {
instrument: "ES1!",
action: "buy",
qty: 1,
orderType: "market",
// limitPrice: 5000.25,
// stopPrice: 4995.00,
// takeProfit: 5020.00,
// stopLoss: 4990.00
};
fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
TOKEN="my-secret-token"
curl -X POST "https://app.crosstrade.io/v1/api/tv/accounts/DEMO12345678/orders/place" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"instrument": "ES1!", "action": "buy", "qty": 1, "orderType": "market"}'
Response
Mutations return the dispatcher envelope. A successful placement includes the Tradovate order id in response.orderId.
{
"success": true,
"destination": "tradovate",
"api": "place_order",
"account": "DEMO12345678",
"instrument": "ES1!",
"response": {
"orderId": 123456789
},
"durationMs": 214
}
Platform nuances
- Body fields use the same camelCase keys as the NT8 REST surface. Enum values stay lowercase (
buy,market), unlike NT8'sBUY/MARKET. takeProfitandstopLossattach a server-side OCO bracket. Use the inline ATM fields for a multi-level bracket.- Account Manager kill and closing-only locks apply. A signal-mode Trade Copier configured on this account fans the order out to its followers.
- On failure, the response is
{"success": false, "error": "<message>"}.
See the Tradovate API overview for the full field grammar, mutation safety guarantees, and error table.