Skip to content

Strategy Global Variables ​

The backtesting engine provides full support for strategy-level global variables, allowing you to define configuration parameters, constants, and settings directly in your strategy code.

Overview ​

Strategy global variables are defined at the top level of your strategy code (outside of any functions) and are accessible within all lifecycle functions (on_strategy_start, on_bar_close, etc.).

python
# Define globals at the top of your strategy
g_fast_period = 12
g_slow_period = 26
DEFAULT_SYMBOLS = ["AAPL", "GOOGL"]

def on_strategy_start(portfolio, state):
    # Globals are accessible here
    print(f"Using SMA periods: {g_fast_period}/{g_slow_period}")
    
def on_bar_close(data_contexts, portfolio, state):
    # And here too!
    for symbol in DEFAULT_SYMBOLS:
        sma_fast = data_contexts[symbol].sma(g_fast_period)

Supported Variable Types ​

All Python data types are supported as strategy globals:

python
# Numbers
g_fast_period = 20
g_risk_percentage = 0.02
g_max_drawdown = 0.15

# Strings  
g_primary_symbol = "AAPL"
g_strategy_name = "SMA Crossover"

# Lists and Tuples
g_symbols = ["AAPL", "GOOGL", "MSFT"]
g_sma_periods = (20, 50, 200)

# Dictionaries
g_position_sizes = {
    "AAPL": 100,
    "GOOGL": 50,  
    "MSFT": 75
}

# Booleans
g_trading_enabled = True
g_use_stop_loss = False

Naming Conventions ​

While any valid Python variable name works, these conventions improve code readability:

python
# Prefix with 'g_' for global parameters
g_fast_period = 20
g_slow_period = 50
g_position_size = 100

# Use 'DEFAULT_' for fallback values
DEFAULT_SYMBOLS = ["AAPL"]
DEFAULT_TIMEFRAME = "1min"

# ALL_CAPS for true constants
MAX_POSITIONS = 5
MIN_PRICE = 1.0
COMMISSION_RATE = 0.001

# lowercase_with_underscores for settings
trading_enabled = True
use_trailing_stops = False
debug_mode = True

Variable Name Examples ​

python
# Technical Analysis Parameters
g_rsi_period = 14
g_bollinger_period = 20
g_macd_fast = 12
g_macd_slow = 26

# Risk Management
g_max_risk_per_trade = 0.02      # 2% per trade
g_max_portfolio_risk = 0.10      # 10% total portfolio
g_stop_loss_pct = 0.05           # 5% stop loss

# Position Sizing  
g_base_position_size = 100
g_max_position_value = 10000
g_position_sizing_method = "fixed"

# Strategy Behavior
g_allow_short_selling = False
g_rebalance_frequency = "daily"
g_market_hours_only = True

Access Patterns ​

The simplest approach is to use globals directly:

python
g_fast_sma = 20
g_slow_sma = 50

def on_bar_close(data_contexts, portfolio, state):
    """Direct access to globals - clean and simple"""
    
    data = data_contexts['AAPL']
    fast_sma = data.sma(g_fast_sma)  # Direct global access
    slow_sma = data.sma(g_slow_sma)  # Direct global access
    
    if fast_sma > slow_sma:
        return {"symbol": "AAPL", "action": "buy", "quantity": 100}
    elif fast_sma < slow_sma:
        return {"symbol": "AAPL", "action": "sell", "quantity": "all"}

Hybrid: Globals + State Overrides ​

For maximum flexibility, combine globals with state parameter access:

python
g_default_symbols = ["AAPL", "GOOGL"]
g_default_period = 20

def on_strategy_start(portfolio, state):
    """Allow API parameters to override strategy defaults"""
    
    # Use API parameter if provided, otherwise use global default
    symbols = state.get('symbols', g_default_symbols)
    period = state.get('sma_period', g_default_period)
    
    print(f"Strategy running on {symbols} with period {period}")
    
    # Store final configuration in state
    state['active_symbols'] = symbols  
    state['active_period'] = period

def on_bar_close(data_contexts, portfolio, state):
    """Use either approach based on your needs"""
    
    # Option 1: Direct global (if no API overrides expected)
    fast_sma = data_contexts['AAPL'].sma(g_default_period)
    
    # Option 2: From state (if API overrides are expected)
    period = state['active_period']
    fast_sma = data_contexts['AAPL'].sma(period)

Complex Configuration Examples ​

Multi-Asset Strategy ​

python
# Symbol-specific configuration
g_symbols_config = {
    "AAPL": {
        "position_size": 100,
        "sma_fast": 10,
        "sma_slow": 30,
        "risk_multiplier": 1.0
    },
    "GOOGL": {
        "position_size": 50, 
        "sma_fast": 15,
        "sma_slow": 45,
        "risk_multiplier": 1.2
    }
}

def on_bar_close(data_contexts, portfolio, state):
    """Use symbol-specific configuration"""
    
    for symbol, config in g_symbols_config.items():
        if symbol not in data_contexts:
            continue
            
        data = data_contexts[symbol]
        fast_sma = data.sma(config["sma_fast"])
        slow_sma = data.sma(config["sma_slow"])
        
        if fast_sma > slow_sma:
            quantity = config["position_size"] * config["risk_multiplier"]
            return {"symbol": symbol, "action": "buy", "quantity": int(quantity)}

Time-Based Configuration ​

python
# Different settings for different market conditions
g_market_regimes = {
    "trending": {
        "sma_fast": 10,
        "sma_slow": 30, 
        "position_size": 150
    },
    "sideways": {
        "sma_fast": 5,
        "sma_slow": 15,
        "position_size": 75
    }
}

g_current_regime = "trending"  # Default regime

def on_strategy_start(portfolio, state):
    """Initialize regime detection"""
    state['market_regime'] = g_current_regime
    print(f"Starting in {g_current_regime} market regime")

def on_bar_close(data_contexts, portfolio, state):
    """Use regime-specific parameters"""
    
    regime = state.get('market_regime', g_current_regime)
    config = g_market_regimes[regime]
    
    data = data_contexts['AAPL']
    fast_sma = data.sma(config["sma_fast"])
    slow_sma = data.sma(config["sma_slow"])
    
    # Trading logic using regime-specific config
    if fast_sma > slow_sma:
        return {
            "symbol": "AAPL", 
            "action": "buy", 
            "quantity": config["position_size"]
        }

Best Practices ​

✅ Do This ​

python
# Clear, descriptive names
g_sma_fast_period = 20
g_sma_slow_period = 50
g_max_position_size = 1000

# Group related configuration
g_risk_management = {
    "max_drawdown": 0.15,
    "stop_loss": 0.05,
    "position_limit": 0.10
}

# Use meaningful defaults
g_default_symbols = ["AAPL", "GOOGL", "MSFT"]
g_trading_hours = {"start": "09:30", "end": "16:00"}

❌ Avoid This ​

python
# Unclear names
a = 20
b = 50
x = 1000

# Magic numbers buried in code
def on_bar_close(data_contexts, portfolio, state):
    sma = data_contexts['AAPL'].sma(20)  # What is 20? Use a global!
    
# Hardcoded values
symbols = ["AAPL"]  # Should be g_symbols or DEFAULT_SYMBOLS

Error Handling ​

The engine provides helpful error messages for undefined variables:

python
def on_strategy_start(portfolio, state):
    # If you reference an undefined global variable:
    period = UNDEFINED_VARIABLE  # This will give a clear error message

Error Message Example:

Variable 'UNDEFINED_VARIABLE' is not defined. Make sure to define 'UNDEFINED_VARIABLE' as a global variable at the top of your strategy code, before any function definitions.

Migration from State-Only Approach ​

If you're currently using only state variables, you can easily migrate:

Before (State-Only) ​

python
def on_strategy_start(portfolio, state):
    state['fast_period'] = 20
    state['slow_period'] = 50
    
def on_bar_close(data_contexts, portfolio, state):
    fast_sma = data_contexts['AAPL'].sma(state['fast_period'])

After (With Globals) ​

python
g_fast_period = 20
g_slow_period = 50

def on_strategy_start(portfolio, state):
    # Globals are automatically available - no setup needed!
    print(f"Using periods: {g_fast_period}/{g_slow_period}")
    
def on_bar_close(data_contexts, portfolio, state):
    fast_sma = data_contexts['AAPL'].sma(g_fast_period)  # Cleaner!

Summary ​

Strategy global variables provide:

  • Natural Python syntax for defining configuration
  • Automatic availability in all lifecycle functions
  • Clear separation between configuration and logic
  • Easy maintenance and parameter adjustment
  • Full compatibility with existing API parameter injection

Define your strategy parameters as globals for the cleanest, most maintainable code!

Test your trading strategies risk-free with professional backtesting.