Skip to content
Back to App

Trades

The Trade endpoint returns the fill history for an account — every executed order that resulted in a position change. Use this to analyze your strategy’s trading activity, calculate performance metrics, or build a trade journal.

Trades vs. Orders

  • Orders are instructions to buy or sell (may be pending, partially filled, filled, or canceled)
  • Trades (also called “fills”) are the actual executions — completed transactions where contracts changed hands

An order with status 2 (Filled) will have a corresponding trade. Pending and canceled orders do not generate trades.


POST Trade/search

Get the trade/fill history for an account. Returns all trades executed during the current session.

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

Authentication: Bearer token required.

Request body

{
"accountId": 12345
}
FieldTypeRequiredDescription
accountIdnumberYesAccount ID

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"trades": [
{
"id": "trd_xyz789",
"orderId": "ord_abc123",
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"side": 0,
"size": 1,
"price": 21503.25,
"timestamp": "2025-01-15T14:30:05Z"
},
{
"id": "trd_xyz790",
"orderId": "ord_def456",
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"side": 1,
"size": 1,
"price": 21518.50,
"timestamp": "2025-01-15T14:45:12Z"
}
]
}
FieldTypeDescription
tradesarrayList of trade/fill objects, ordered chronologically
trades[].idstringUnique trade identifier
trades[].orderIdstringThe order ID that generated this trade
trades[].accountIdnumberAccount ID
trades[].contractIdstringContract ID
trades[].sidenumber0 = Buy, 1 = Sell
trades[].sizenumberNumber of contracts filled
trades[].pricenumberExecution price
trades[].timestampstringISO 8601 timestamp of the fill

Example

result = api("Trade/search", {"accountId": ACCOUNT_ID})
if result["success"]:
trades = result.get("trades", [])
print(f"Total trades: {len(trades)}")
for trade in trades:
side = "BUY" if trade["side"] == 0 else "SELL"
print(f" {trade['timestamp']}{side} {trade['size']} @ {trade['price']}")

Calculating performance from trades

You can compute key performance metrics directly from the trade history:

Total P&L

result = api("Trade/search", {"accountId": ACCOUNT_ID})
trades = result.get("trades", [])
# Pair up buy/sell trades to calculate round-trip P&L
total_pnl = 0.0
buys = []
for trade in trades:
if trade["side"] == 0: # Buy
buys.append(trade)
elif trade["side"] == 1 and buys: # Sell (close)
entry = buys.pop(0)
pnl = (trade["price"] - entry["price"]) * trade["size"] * TICK_VALUE / TICK_SIZE
total_pnl += pnl
print(f"Total P&L: ${total_pnl:,.2f}")

Win rate

wins = 0
losses = 0
round_trips = []
# Pair trades into round trips
for i in range(0, len(trades) - 1, 2):
entry = trades[i]
exit_trade = trades[i + 1]
if entry["side"] == 0: # Long trade
pnl = exit_trade["price"] - entry["price"]
else: # Short trade
pnl = entry["price"] - exit_trade["price"]
if pnl > 0:
wins += 1
elif pnl < 0:
losses += 1
round_trips.append(pnl)
total_trades = wins + losses
win_rate = (wins / total_trades * 100) if total_trades > 0 else 0
print(f"Win rate: {win_rate:.1f}% ({wins}W / {losses}L)")

Trade count and frequency

from datetime import datetime
trades = result.get("trades", [])
if len(trades) >= 2:
first = datetime.fromisoformat(trades[0]["timestamp"].replace("Z", "+00:00"))
last = datetime.fromisoformat(trades[-1]["timestamp"].replace("Z", "+00:00"))
duration = last - first
print(f"Session duration: {duration}")
print(f"Trades: {len(trades)} over {duration}")

Usage notes

  • Trades are returned in chronological order (oldest first).
  • Each fill is a separate trade object, even if the order was partially filled across multiple prices.
  • The trade list is scoped to the current replay session. Starting a new session resets the trade history.
  • Use Trade/search after calling Replay/end to get the complete trade log for a session. The session results include an aggregate summary, while Trade/search gives you the individual fill details.