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:
- TestMax reads your configuration (instrument, dates, timeframe, speed, template parameters)
- These values are set as environment variables in the Python process
- The script header reads them with
os.environ.get("VAR_NAME", "default") - 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:
| Variable | Example Value | Description |
|---|---|---|
TESTMAX_API_URL | http://localhost:8087/api/topstep-sim | Base URL for the TestMax simulator API |
TESTMAX_TOKEN | eyJhbGci... | Authentication token for API requests |
INSTRUMENT | NQ | Instrument symbol selected in the UI |
START_DATE | 2025-01-15 | Start date for the backtest (YYYY-MM-DD) |
END_DATE | 2025-01-15 | End date for the backtest (YYYY-MM-DD) |
TIMEFRAME | 1m | Bar timeframe: 1s, 5s, 1m, 5m, or 15m |
STEP_DELAY | 0.02 | Initial delay between bars in seconds (based on speed setting) |
SPEED_FILE | /tmp/speed_abc123.txt | Path 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:
| Variable | Example Value | Description |
|---|---|---|
ACCOUNT_ID | 12345 | The simulator account ID for this session |
CONTRACT_ID | CON.F.US.ENQ.H25 | The contract ID for the selected instrument |
TOTAL_BARS | 390 | Total 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
| Variable | Default | Description |
|---|---|---|
FAST_PERIOD | 10 | Number of bars for the fast moving average |
SLOW_PERIOD | 30 | Number of bars for the slow moving average |
MAX_BARS | 0 | Maximum bars to process (0 = unlimited) |
RSI Scalper
| Variable | Default | Description |
|---|---|---|
RSI_PERIOD | 14 | Number of bars for RSI calculation |
OVERBOUGHT | 70 | RSI level considered overbought |
OVERSOLD | 30 | RSI level considered oversold |
MAX_BARS | 0 | Maximum bars to process (0 = unlimited) |
Channel Breakout
| Variable | Default | Description |
|---|---|---|
LOOKBACK | 50 | Number of bars for channel calculation |
MAX_BARS | 0 | Maximum bars to process (0 = unlimited) |
Custom
| Variable | Default | Description |
|---|---|---|
MAX_BARS | 0 | Maximum 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 parametersFAST_PERIOD = int(os.environ.get("FAST_PERIOD", "10"))MAX_BARS = int(os.environ.get("MAX_BARS", "0"))
# Float parametersTHRESHOLD = 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 defaultRSI_PERIOD = int(os.environ.get("RSI_PERIOD", "14"))
# Bad — will crash if not setRSI_PERIOD = int(os.environ["RSI_PERIOD"]) # KeyError if not setThe 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
0and TOTAL_BARS is390, 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 defaultsENTRY_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 Setting | Approximate STEP_DELAY | Effect |
|---|---|---|
| 1x | 1.0 | One bar per second — slow, good for watching individual trades |
| 2x | 0.5 | Two bars per second |
| 5x | 0.2 | Five bars per second |
| 10x | 0.1 | Ten bars per second — good default for development |
| 25x | 0.04 | Fast, chart still updates visibly |
| 50x | 0.02 | Very fast |
| 100x | 0.01 | Near-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:
| Variable | TestMax Value | Live TopStep Value |
|---|---|---|
TESTMAX_API_URL | http://localhost:8087/api/topstep-sim | https://api.topstepx.com/api |
TESTMAX_TOKEN | TestMax session token | Your TopStep API token |
SPEED_FILE | Path to speed control file | Not used (remove read_speed() calls) |
ACCOUNT_ID | Set by Playground | Your TopStep account ID |
CONTRACT_ID | Set by Playground | The 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.