TopStep Compatibility
One of the most powerful features of the Algo Playground is that your Python strategies use the exact same API as the real TopStep ProjectX Gateway. This means the code you develop and test in TestMax can be adapted for live trading with minimal changes.
How compatibility works
The TestMax simulator implements the same REST API endpoints as the TopStep ProjectX Gateway:
| Endpoint | TestMax | TopStep Live | Behavior |
|---|---|---|---|
Account/search | Simulator account | Real funded account | Returns account info |
Order/place | Fills against historical data | Fills against live market | Places a trading order |
Position/searchOpen | Simulated positions | Real positions | Returns open positions |
Trade/search | Simulated trade history | Real trade history | Returns past trades |
The API request and response formats are identical. When your strategy calls place_order(ACCOUNT_ID, CONTRACT_ID, 0, 1), the same JSON payload is sent whether you are backtesting in TestMax or trading live on TopStep.
What is the same
- All API endpoint paths —
Order/place,Account/search,Position/searchOpen, etc. - Request body format — Same JSON structure for all parameters
- Response body format — Same fields in all responses
- Authentication — Both use Bearer token in the Authorization header
- Order types — Market (2), Limit (1), Stop (4) all work identically
- Side values — Buy (0) and Sell (1) are the same
- Contract IDs — Same format (e.g.,
CON.F.US.ENQ.H25)
What is different
| Aspect | TestMax (Backtest) | TopStep (Live) |
|---|---|---|
| API base URL | http://localhost:8087/api/topstep-sim | https://api.topstepx.com/api |
| Data feed | get_next_bar() via Replay API | SignalR WebSocket real-time feed |
| Execution speed | Controlled by speed slider | Real-time only |
| Risk | No real money | Real money at stake |
| Market hours | Any historical date/time | Live market hours only |
| Session management | Replay/start and Replay/end | No replay — market is always live |
Migrating to live trading
To adapt a TestMax strategy for live trading on TopStep, you need to make three changes:
-
Change the API URL
Replace the TestMax simulator URL with the TopStep production API:
# TestMax (backtesting)API_URL = "http://localhost:8087/api/topstep-sim"# TopStep (live trading)API_URL = "https://api.topstepx.com/api" -
Replace get_next_bar() with a real-time data feed
In TestMax,
get_next_bar()fetches the next historical bar from the replay. In live trading, you need to subscribe to real-time market data via TopStep’s SignalR WebSocket connection.# Replay-based — pulls one bar at a timedef get_next_bar():result = api("Replay/step", {"accountId": ACCOUNT_ID, "steps": 1})bars = result.get("bars", [])if not bars:return Nonereturn bars[0]# Main loopfor i in range(MAX_BARS):bar = get_next_bar()if bar is None:break# ... strategy logic ...# Real-time — receives bars via WebSocket callback# (Requires signalrcore or similar library)from signalrcore.hub_connection_builder import HubConnectionBuilderbars_queue = []def on_bar(bar_data):"""Called by SignalR when a new bar arrives."""bars_queue.append(bar_data)# Set up SignalR connectionhub = HubConnectionBuilder() \.with_url("https://rtc.topstepx.com/hubs/market",options={"access_token_factory": lambda: TOKEN}) \.build()hub.on("GatewayQuote", on_bar)hub.start()# Main loop — wait for bars instead of pulling themwhile True:if bars_queue:bar = bars_queue.pop(0)# ... strategy logic (same as backtest) ...else:time.sleep(0.1) # Wait for next bar -
Remove backtest-specific code
Remove or adapt these backtest-only elements:
read_speed()andtime.sleep(STEP_DELAY)— Not needed in live trading. The market sets the pace.Replay/startandReplay/end— No replay sessions in live trading.SPEED_FILE— Not applicable.- The cleanup section — In live trading, you may want to keep positions open rather than flattening at the end of a script run.
What stays the same
The core trading logic — the part that makes decisions — is identical between backtesting and live trading:
# This code works in BOTH TestMax and live TopStep:if fast_ma > slow_ma and position != "LONG": if position == "SHORT": place_order(ACCOUNT_ID, CONTRACT_ID, 0, 2) else: place_order(ACCOUNT_ID, CONTRACT_ID, 0, 1) position = "LONG" entry_price = price print(f"[TRADE] BUY @ {price:.2f}")The place_order(), get_positions(), close_all_positions(), get_account(), and api() functions all work unchanged on the live TopStep API. The request format, response format, and behavior are the same.
Side-by-side comparison
Here is a complete minimal strategy showing both versions:
#!/usr/bin/env python3import os, sys, json, time, urllib.request, urllib.error
API_URL = os.environ.get("TESTMAX_API_URL")TOKEN = os.environ.get("TESTMAX_TOKEN")SPEED_FILE = os.environ.get("SPEED_FILE", "")STEP_DELAY = float(os.environ.get("STEP_DELAY", "0.02"))
# ... api helpers (same) ...
# Backtest session setupsession = api("Replay/start", { "instrumentSymbol": "NQ", "startDate": "2025-01-15", "timeframe": "1m",})ACCOUNT_ID = session["accountId"]CONTRACT_ID = session["instrument"]["contractId"]
def get_next_bar(): result = api("Replay/step", {"accountId": ACCOUNT_ID, "steps": 1}) bars = result.get("bars", []) return bars[0] if bars else None
# Strategy looptry: for i in range(999999): bar = get_next_bar() if bar is None: break read_speed() if STEP_DELAY > 0: time.sleep(STEP_DELAY)
# ... trading logic ...
finally: close_all_positions(ACCOUNT_ID, CONTRACT_ID) api("Replay/end", {"accountId": ACCOUNT_ID})#!/usr/bin/env python3import os, sys, json, time, urllib.request, urllib.error
API_URL = "https://api.topstepx.com/api"TOKEN = os.environ.get("TOPSTEP_TOKEN")
# ... api helpers (same) ...
# Get account (no replay session needed)account = get_account()ACCOUNT_ID = account["id"]CONTRACT_ID = "CON.F.US.ENQ.H25" # Or look up dynamically
# Subscribe to real-time data (replace get_next_bar)# ... SignalR WebSocket setup ...
# Strategy loopwhile True: bar = wait_for_next_bar() # From WebSocket if bar is None: continue
# ... trading logic (IDENTICAL to backtest) ...
# No automatic cleanup — manage positions manuallyMigration checklist
Before running your strategy live, verify each of these items:
- API URL changed to
https://api.topstepx.com/api - Authentication token is a valid TopStep API token (not a TestMax token)
- Data feed uses SignalR WebSocket instead of
get_next_bar() - Speed control removed (
read_speed()andtime.sleep(STEP_DELAY)) - Replay endpoints removed (
Replay/start,Replay/step,Replay/end) - Account ID and Contract ID are set to your real TopStep account values
- Error handling is robust — the strategy gracefully handles API failures, disconnections, and unexpected responses
- Risk management is in place — stop-losses, position size limits, and daily loss limits
- Strategy has been backtested on multiple dates with consistent positive results
- You understand the risks of live trading with real money
TopStep API documentation
For complete TopStep API documentation, including SignalR WebSocket setup and all available endpoints, refer to:
- TopStep API Reference — TestMax’s documentation of the TopStep-compatible API
- Authentication — How to obtain and use API tokens
- Orders — Complete order placement documentation
- Positions — Position management endpoints
Frequently asked questions
Do I need a TopStep account to use the Algo Playground? No. The Algo Playground uses TestMax’s built-in simulator, which implements the TopStep API. You only need a TopStep account if you want to trade live.
Can I use my TopStep demo account with TestMax strategies? Not directly through the Playground. However, you can take the Python script (visible in the Code tab), modify it for live use as described above, and run it independently against your TopStep account.
Will my strategy perform the same in live trading? Not necessarily. Backtesting uses historical data with deterministic fills. Live trading introduces latency, slippage, partial fills, and market conditions that may differ from historical patterns. Use backtesting to validate your logic, but expect some difference in live performance.
What Python libraries do I need for live trading?
The core API functions use only Python standard library (urllib). For the SignalR WebSocket data feed, you will need the signalrcore package or a similar SignalR client library. Install it with pip install signalrcore.