Skip to content
Back to App

Environment Variables

TestMax passes configuration to your Python strategy through environment variables. This keeps the strategy code clean and makes it easy to change settings without modifying the script itself.

How environment variables work

When you click “Run Backtest” in the Playground:

  1. TestMax reads your configuration (instrument, dates, timeframe, speed, template parameters)
  2. These values are set as environment variables in the Python process
  3. The script header reads them with os.environ.get("VAR_NAME", "default")
  4. Your strategy code can also read custom parameters the same way

Variable reference

Core configuration

These variables are set by the Playground for every run:

VariableExample ValueDescription
TESTMAX_API_URLhttp://localhost:8087/api/topstep-simBase URL for the TestMax simulator API
TESTMAX_TOKENeyJhbGci...Authentication token for API requests
INSTRUMENTNQInstrument symbol selected in the UI
START_DATE2025-01-15Start date for the backtest (YYYY-MM-DD)
END_DATE2025-01-15End date for the backtest (YYYY-MM-DD)
TIMEFRAME1mBar timeframe: 1s, 5s, 1m, 5m, or 15m
STEP_DELAY0.02Initial delay between bars in seconds (based on speed setting)
SPEED_FILE/tmp/speed_abc123.txtPath to the file where the UI writes speed changes

Session variables

These are set by the Playground after the replay session is created, before the script starts:

VariableExample ValueDescription
ACCOUNT_ID12345The simulator account ID for this session
CONTRACT_IDCON.F.US.ENQ.H25The contract ID for the selected instrument
TOTAL_BARS390Total number of bars available in the session

Template parameters

Template-specific parameters are passed as environment variables with the same name as the parameter. These are set based on the values you enter in the sidebar:

SMA Crossover

VariableDefaultDescription
FAST_PERIOD10Number of bars for the fast moving average
SLOW_PERIOD30Number of bars for the slow moving average
MAX_BARS0Maximum bars to process (0 = unlimited)

RSI Scalper

VariableDefaultDescription
RSI_PERIOD14Number of bars for RSI calculation
OVERBOUGHT70RSI level considered overbought
OVERSOLD30RSI level considered oversold
MAX_BARS0Maximum bars to process (0 = unlimited)

Channel Breakout

VariableDefaultDescription
LOOKBACK50Number of bars for channel calculation
MAX_BARS0Maximum bars to process (0 = unlimited)

Custom

VariableDefaultDescription
MAX_BARS0Maximum bars to process (0 = unlimited)

Reading environment variables in your strategy

All environment variables are strings. You need to cast them to the appropriate type:

# Integer parameters
FAST_PERIOD = int(os.environ.get("FAST_PERIOD", "10"))
MAX_BARS = int(os.environ.get("MAX_BARS", "0"))
# Float parameters
THRESHOLD = float(os.environ.get("THRESHOLD", "0.5"))
RISK_PCT = float(os.environ.get("RISK_PCT", "0.02"))
# String parameters (no cast needed)
INSTRUMENT = os.environ.get("INSTRUMENT", "NQ")
# Boolean parameters (env vars are always strings)
USE_FILTER = os.environ.get("USE_FILTER", "true").lower() == "true"

The default value pattern

os.environ.get("VAR_NAME", "default") returns the environment variable value if set, or the default string if not. Always provide a sensible default so your strategy works even when a variable is not explicitly set:

# Good — has a default
RSI_PERIOD = int(os.environ.get("RSI_PERIOD", "14"))
# Bad — will crash if not set
RSI_PERIOD = int(os.environ["RSI_PERIOD"]) # KeyError if not set

The MAX_BARS pattern

All templates use this pattern to handle the MAX_BARS variable:

MAX_BARS = int(os.environ.get("MAX_BARS", "0")) or int(os.environ.get("TOTAL_BARS", "999999"))

The or operator in Python returns the first truthy value. Since int("0") is 0 (falsy), when MAX_BARS is not set or is set to 0, the expression falls through to TOTAL_BARS. This means:

  • If the user set MAX_BARS to 500, the strategy processes 500 bars
  • If MAX_BARS is 0 and TOTAL_BARS is 390, the strategy processes 390 bars
  • If neither is set, the strategy processes 999999 bars (effectively unlimited)

Defining custom parameters

When writing a custom strategy, you can define your own parameters by reading from environment variables. While the Playground UI only shows parameters defined in the template configuration, you can hard-code values or use environment variable defaults:

# Custom parameters with defaults
ENTRY_THRESHOLD = float(os.environ.get("ENTRY_THRESHOLD", "2.5"))
EXIT_THRESHOLD = float(os.environ.get("EXIT_THRESHOLD", "1.0"))
POSITION_SIZE = int(os.environ.get("POSITION_SIZE", "1"))
USE_STOP_LOSS = os.environ.get("USE_STOP_LOSS", "true").lower() == "true"
STOP_POINTS = float(os.environ.get("STOP_POINTS", "10.0"))

Speed and step delay

The relationship between the speed slider and the STEP_DELAY variable:

Speed SettingApproximate STEP_DELAYEffect
1x1.0One bar per second — slow, good for watching individual trades
2x0.5Two bars per second
5x0.2Five bars per second
10x0.1Ten bars per second — good default for development
25x0.04Fast, chart still updates visibly
50x0.02Very fast
100x0.01Near-instant, chart updates are rapid

The SPEED_FILE variable points to a temporary file that the Playground UI updates when you move the speed slider. The read_speed() function reads this file on each bar to pick up changes:

# This happens automatically inside read_speed():
with open(SPEED_FILE) as f:
STEP_DELAY = max(0, float(f.read().strip()))

Environment variables for live trading

If you adapt your strategy for live trading on TopStep (see TopStep Compatibility), you would set these environment variables differently:

VariableTestMax ValueLive TopStep Value
TESTMAX_API_URLhttp://localhost:8087/api/topstep-simhttps://api.topstepx.com/api
TESTMAX_TOKENTestMax session tokenYour TopStep API token
SPEED_FILEPath to speed control fileNot used (remove read_speed() calls)
ACCOUNT_IDSet by PlaygroundYour TopStep account ID
CONTRACT_IDSet by PlaygroundThe contract you want to trade

The INSTRUMENT, START_DATE, END_DATE, TIMEFRAME, and TOTAL_BARS variables are not used in live trading — they are specific to the backtesting replay system.