Debugging & Errors
When your strategy does not behave as expected, the Playground provides several tools to help you find and fix the problem. This page covers how to use print statements for debugging, how to read error messages, and solutions for the most common issues.
Debugging with print()
The simplest and most effective debugging tool is print(). Everything you print is streamed in real time to the Output tab in the Playground. Use the standard log prefix conventions so your messages are easy to scan:
# Info messages — general statusprint(f"[INFO] Bar {i}: price={price:.2f}, sma={fast_ma:.2f}")
# Trade messages — when orders are placedprint(f"[TRADE] BUY @ {price:.2f} | Reason: RSI={rsi:.1f}")
# Error messages — when something goes wrongprint(f"[ERROR] Unexpected position state: {position}")
# Debug messages — temporary, remove before final runsprint(f"[DEBUG] closes[-5:] = {closes[-5:]}")print(f"[DEBUG] condition check: fast={fast_ma}, slow={slow_ma}, pos={position}")Debugging tips
- Print indicator values on every bar during development. This lets you verify that your calculations are correct before acting on signals.
- Print the bar data to confirm you are reading the right fields:
print(f"[DEBUG] bar = {bar}") - Print before and after orders to confirm they execute:
print(f"[DEBUG] About to place order...")thenresult = place_order(...)thenprint(f"[DEBUG] Order result: {result}") - Use MAX_BARS=50 during debugging. Processing 50 bars takes seconds instead of minutes, letting you iterate quickly.
- Remove or comment out debug prints before running full backtests. Printing on every bar slows down execution and floods the output.
Reading the output log
The Output tab shows everything your script prints to stdout and stderr. Messages appear in real time as the backtest runs.
Log prefixes
| Prefix | Source | Meaning |
|---|---|---|
[INFO] | Your strategy or setup code | Status and configuration messages |
[TRADE] | Your strategy | A trade was placed |
[ERROR] | Your strategy or API helper | Something went wrong |
[DONE] | Cleanup code | Final results |
[DEBUG] | Your strategy (convention) | Temporary debugging output |
Stderr output
The api() function prints errors to stderr (file=sys.stderr). These also appear in the Output tab but may be interleaved with stdout messages. Look for lines starting with [ERROR] API — these indicate API call failures.
Common errors and solutions
”No more bars available” immediately
[INFO] Account: 12345, Contract: CON.F.US.ENQ.H25, Bars: 0[INFO] No more bars availableCause: The replay session returned 0 bars. This usually means:
- The date range has no data for the selected instrument
- The start date is a weekend or market holiday
- The instrument was not traded on that date
Fix: Choose a date that falls on a weekday when the market was open. For US futures (NQ, ES), this means Monday through Friday, excluding holidays. Try a known good date like 2025-01-15 (a Wednesday).
API error 400 on order placement
[ERROR] API Order/place: 400 {"errorMessage": "Invalid size"}Cause: The order parameters are invalid. Common reasons:
sizeis 0 or negativesideis not 0 or 1order_typeis not 1, 2, or 4limit_priceis missing for a limit order (type 1)stop_priceis missing for a stop order (type 4)
Fix: Check that all parameters have valid values. Print them before calling place_order():
print(f"[DEBUG] Placing order: side={side}, size={size}, type={order_type}")result = place_order(ACCOUNT_ID, CONTRACT_ID, side, size, order_type)print(f"[DEBUG] Result: {result}")API error 401 (Unauthorized)
[ERROR] API Order/place: 401Cause: The authentication token is invalid or expired.
Fix: This should not happen during normal Playground usage — the token is set automatically. If you see this, try refreshing the page and running the backtest again. If it persists, log out and log back in.
NameError: variable not defined
[ERROR] Cleanup failed: name 'trade_count' is not definedCause: Your strategy code has a bug that prevents it from reaching the variable definition. For example, if your code crashes before trade_count = 0 is executed, the cleanup section cannot reference it.
Fix: Always define tracking variables (trade_count, wins, entry_price, position) at the very top of your strategy section, before any logic that could fail:
# Define these FIRST, before any logiccloses = []position = Nonetrade_count = 0wins = 0entry_price = 0
# Now your logic that might failtry: for i in range(MAX_BARS): # ...SyntaxError in strategy code
SyntaxError: invalid syntax (script.py, line 85)Cause: Your Python code has a syntax error — a missing colon, unmatched parenthesis, incorrect indentation, etc.
Fix: Check the line number reported in the error. Common syntax issues:
- Missing
:afterif,for,def,try,except,finallystatements - Mismatched parentheses
(), brackets[], or braces{} - Incorrect indentation (Python is whitespace-sensitive)
- Using
=instead of==in comparisons
TypeError: subscript or operation error
TypeError: 'NoneType' object is not subscriptableCause: You are trying to access fields on a None value. This usually happens when get_next_bar() returns None and you do not check for it before accessing bar["c"].
Fix: Always check for None immediately after calling get_next_bar():
bar = get_next_bar()if bar is None: break # Exit the loop
# Now safe to access bar fieldsprice = bar["c"]Strategy runs but places no trades
Cause: Your entry conditions are never met. Common reasons:
- Not enough bars to compute indicators (e.g., 30-period SMA needs 30 bars)
- Conditions are too restrictive (e.g., RSI rarely drops below 20)
- Logic error in the condition (e.g., using
andwhen you meantor) - The
continuestatement skips the trading logic
Fix: Add print statements to check your indicator values and conditions:
if len(closes) >= SLOW_PERIOD: fast_ma = sma(closes, FAST_PERIOD) slow_ma = sma(closes, SLOW_PERIOD) print(f"[DEBUG] Bar {i}: fast={fast_ma:.2f}, slow={slow_ma:.2f}, diff={fast_ma-slow_ma:.2f}")If the indicator values look correct but no trades fire, check the position guard:
# This prevents re-entering the same directionif fast_ma > slow_ma and position != "LONG": # ...If position is already "LONG" from a previous signal, the condition will not trigger. Make sure position tracking is correct.
Strategy is very slow
Cause: The strategy is doing too much work per bar, or the speed is set too low.
Fix:
- Increase the speed slider to 50x or 100x
- Reduce the amount of data processing per bar. For example, avoid recalculating indicators from scratch on every bar if you can maintain a running calculation.
- Remove excessive print statements. Each
print()call adds overhead because the output is streamed to the browser. - Use a longer timeframe (1m instead of 1s) to reduce the total number of bars.
WebSocket disconnection
If the chart stops updating but the Output tab still shows messages, the WebSocket connection may have dropped.
Fix: The Playground will attempt to reconnect automatically. If the chart remains frozen, stop the backtest and start a new one. The results up to the disconnection point are still valid.
Debugging workflow
Here is a recommended workflow for debugging a misbehaving strategy:
- Set MAX_BARS to 50-100. This limits execution to a small sample so you can iterate quickly.
- Add print statements before and after your key logic points.
- Run the backtest and check the Output tab.
- Verify indicator calculations. Compare your computed values against what you expect for the given price data.
- Check order placement. Print the result of
place_order()to confirm orders are accepted. - Check position tracking. Print the
positionvariable after each trade to ensure it updates correctly. - Run a full backtest. Once everything looks correct on a small sample, remove debug prints and run with MAX_BARS=0.
Viewing the full script
Switch to the Code tab in the bottom panel to see the complete assembled Python script. This is the exact code being executed on the server, including:
- The auto-generated header with all imports and API helpers
- Your strategy parameters
- The backtest setup code
- Your strategy logic
- The cleanup code
When an error reports a line number, use the Code tab to find the corresponding line. The Code tab is read-only — it reflects the script that was generated when you clicked Run.