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/sim/Trade/search

Authentication: Bearer token required.

Request body

{
"accountId": 12345,
"startTimestamp": "2025-01-15T00:00:00Z",
"endTimestamp": "2025-01-16T00:00:00Z"
}
FieldTypeRequiredDescription
accountIdnumberYesAccount ID
startTimestampstringNoOnly return fills at or after this time
endTimestampstringNoOnly return fills at or before this time

Response

Returns up to 500 fills, newest first.

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"trades": [
{
"id": 2,
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"creationTimestamp": "2025-01-15T14:45:12.000Z",
"price": 21518.50,
"profitAndLoss": null,
"fees": 1.24,
"side": 1,
"size": 1,
"voided": false,
"orderId": 1000000043
},
{
"id": 1,
"accountId": 12345,
"contractId": "CON.F.US.ENQ.H25",
"creationTimestamp": "2025-01-15T14:30:05.000Z",
"price": 21503.25,
"profitAndLoss": null,
"fees": 1.24,
"side": 0,
"size": 1,
"voided": false,
"orderId": 1000000042
}
]
}
FieldTypeDescription
tradesarrayList of trade/fill objects, newest first
trades[].idnumberTrade index within the response
trades[].accountIdnumberAccount ID
trades[].contractIdstringContract ID
trades[].creationTimestampstringISO 8601 timestamp of the fill
trades[].pricenumberExecution price
trades[].profitAndLossnullAlways null — fills are half-turns; compute round-trip P&L yourself
trades[].feesnumberCommission/fees charged on the fill
trades[].sidenumber0 = Buy, 1 = Sell
trades[].sizenumberNumber of contracts filled
trades[].voidedbooleanAlways false
trades[].orderIdnumberThe order ID that generated this trade

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['creationTimestamp']} — {side} {trade['size']} @ {trade['price']}")

Calculating performance from trades

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

Total P&L

This FIFO example supports long and short positions, partial exits, and reversals. Use a complete fill history starting from a flat position, for one contract, with TICK_VALUE and TICK_SIZE set for that contract. Trade/search returns at most 500 fills: a truncated response or a timestamp filter that omits entries cannot produce reliable P&L. For a full run, use the final account balance from Replay/end minus the starting balance for net realized P&L after positions are flattened, assuming no other balance adjustments.

from collections import deque
result = api("Trade/search", {"accountId": ACCOUNT_ID})
if not result["success"]:
raise RuntimeError(result.get("errorMessage"))
trades = sorted(result.get("trades", []), key=lambda t: t["creationTimestamp"])
entries = deque()
round_trips = []
gross_pnl = 0.0
fees = sum(trade["fees"] for trade in trades)
for trade in trades:
direction = 1 if trade["side"] == 0 else -1
remaining = trade["size"]
while remaining and entries and entries[0]["direction"] != direction:
entry = entries[0]
quantity = min(remaining, entry["remaining"])
pnl = (trade["price"] - entry["price"]) * entry["direction"] * quantity * TICK_VALUE / TICK_SIZE
gross_pnl += pnl
round_trips.append(pnl)
remaining -= quantity
entry["remaining"] -= quantity
if entry["remaining"] == 0:
entries.popleft()
if remaining:
entries.append({"direction": direction, "price": trade["price"], "remaining": remaining})
net_pnl = gross_pnl - fees
print(f"Gross realized P&L: ${gross_pnl:,.2f}")
print(f"Fill fees: ${fees:,.2f}")
print(f"Net realized P&L after all fill fees: ${net_pnl:,.2f}")

Gross realized P&L excludes fees. Net realized P&L subtracts all returned fill fees, including fees on any still-open entries; neither value includes unrealized P&L on those entries. When all positions are closed, net P&L includes both entry and exit fees.

Win rate of matched exit portions

Reuse round_trips from the FIFO example above. Each matched exit portion counts once, so scaling out can produce several results for one position. This is a gross win rate before fees, rather than the app’s closed-position win rate.

wins = sum(pnl > 0 for pnl in round_trips)
losses = sum(pnl < 0 for pnl in round_trips)
total_trades = wins + losses
win_rate = (wins / total_trades * 100) if total_trades > 0 else 0
print(f"Gross win rate of matched exit portions: {win_rate:.1f}% ({wins}W / {losses}L)")

Trade count and frequency

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

Usage notes

  • Trades are returned newest first (up to 500). Sort by creationTimestamp if you need chronological order.
  • 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. Replay/end returns only the final account snapshot (balance and equity), while Trade/search gives you the individual fill details.