Skip to content
Back to App

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 status
print(f"[INFO] Bar {i}: price={price:.2f}, sma={fast_ma:.2f}")
# Trade messages — when orders are placed
print(f"[TRADE] BUY @ {price:.2f} | Reason: RSI={rsi:.1f}")
# Error messages — when something goes wrong
print(f"[ERROR] Unexpected position state: {position}")
# Debug messages — temporary, remove before final runs
print(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...") then result = place_order(...) then print(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

PrefixSourceMeaning
[INFO]Your strategy or setup codeStatus and configuration messages
[TRADE]Your strategyA trade was placed
[ERROR]Your strategy or API helperSomething went wrong
[DONE]Cleanup codeFinal 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 available

Cause: 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:

  • size is 0 or negative
  • side is not 0 or 1
  • order_type is not 1, 2, or 4
  • limit_price is missing for a limit order (type 1)
  • stop_price is 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: 401

Cause: 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 defined

Cause: 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 logic
closes = []
position = None
trade_count = 0
wins = 0
entry_price = 0
# Now your logic that might fail
try:
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 : after if, for, def, try, except, finally statements
  • 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 subscriptable

Cause: 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 fields
price = 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 and when you meant or)
  • The continue statement 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 direction
if 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:

  1. Set MAX_BARS to 50-100. This limits execution to a small sample so you can iterate quickly.
  2. Add print statements before and after your key logic points.
  3. Run the backtest and check the Output tab.
  4. Verify indicator calculations. Compare your computed values against what you expect for the given price data.
  5. Check order placement. Print the result of place_order() to confirm orders are accepted.
  6. Check position tracking. Print the position variable after each trade to ensure it updates correctly.
  7. 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.