Skip to content

Risk Management Best Practices

Essential techniques for protecting your capital and maximizing long-term returns.

Core Principles

1. Never Risk More Than You Can Afford to Lose

python
# Risk no more than 2% of account per trade
MAX_RISK_PER_TRADE = 0.02

def calculate_position_size(portfolio, entry_price, stop_loss_price):
    account_risk = portfolio.equity * MAX_RISK_PER_TRADE
    risk_per_share = abs(entry_price - stop_loss_price)
    shares = int(account_risk / risk_per_share)
    return shares

2. Position Sizing is Everything

python
def position_sizing_example(portfolio, data):
    """Different position sizing methods"""
    
    # Fixed dollar amount
    fixed_amount = 10000
    shares_fixed = int(fixed_amount / data.close)
    
    # Fixed percentage of portfolio
    portfolio_pct = 0.20  # 20% of portfolio
    shares_pct = int((portfolio.equity * portfolio_pct) / data.close)
    
    # Volatility-based sizing
    volatility = calculate_volatility(data)  # Custom function
    shares_vol = int((portfolio.equity * 0.15) / (volatility * data.close))
    
    # Use the most conservative
    return min(shares_fixed, shares_pct, shares_vol)

3. Always Use Stop Losses

python
def strategy_with_stops(data_contexts, portfolio, state):
    data = data_contexts['AAPL']
    current_pos = portfolio.position('AAPL')
    
    # Entry logic
    if should_buy() and current_pos == 0:
        entry_price = data.close
        stop_price = entry_price * 0.95  # 5% stop loss
        
        # Calculate position size based on stop
        shares = calculate_position_size(portfolio, entry_price, stop_price)
        
        # Store stop price for exit logic
        state['stop_price'] = stop_price
        state['entry_price'] = entry_price
        
        return {'symbol': 'AAPL', 'action': 'buy', 'quantity': shares}
    
    # Stop loss exit
    elif current_pos > 0 and data.close <= state.get('stop_price', 0):
        print(f"STOP LOSS HIT: {data.close} <= {state['stop_price']}")
        return {'symbol': 'AAPL', 'action': 'sell', 'quantity': 'all'}
    
    return None

Position Sizing Strategies

Kelly Criterion

python
def kelly_position_size(win_rate, avg_win, avg_loss, portfolio_equity):
    """Optimal position size using Kelly Criterion"""
    if avg_loss == 0:
        return 0
    
    win_loss_ratio = avg_win / abs(avg_loss)
    kelly_pct = win_rate - ((1 - win_rate) / win_loss_ratio)
    
    # Use fractional Kelly (25% of full Kelly) for safety
    safe_kelly = max(0, min(0.25, kelly_pct * 0.25))
    
    return portfolio_equity * safe_kelly

Risk Parity

python
def risk_parity_sizing(symbols, data_contexts, portfolio):
    """Equal risk contribution from each position"""
    total_risk_budget = portfolio.equity * 0.10  # 10% total risk
    risk_per_asset = total_risk_budget / len(symbols)
    
    positions = {}
    for symbol in symbols:
        data = data_contexts[symbol]
        volatility = calculate_volatility(data, 20)  # 20-day volatility
        
        # Position size = Risk Budget / (Price * Volatility)
        position_value = risk_per_asset / volatility
        shares = int(position_value / data.close)
        positions[symbol] = shares
    
    return positions

Stop Loss Techniques

Fixed Percentage Stop

python
def fixed_stop_loss(entry_price, stop_pct=0.05):
    return entry_price * (1 - stop_pct)

ATR-Based Stop

python
def atr_stop_loss(data, entry_price, atr_multiple=2.0):
    """Stop based on Average True Range"""
    # ATR approximation using high-low range
    ranges = []
    for i in range(min(14, len(data.history('high', 14)))):
        high = data.history('high', 14)[i]
        low = data.history('low', 14)[i]
        ranges.append(high - low)
    
    atr = sum(ranges) / len(ranges)
    stop_distance = atr * atr_multiple
    
    return entry_price - stop_distance

Trailing Stop

python
def trailing_stop_strategy(data_contexts, portfolio, state):
    data = data_contexts['AAPL']
    current_pos = portfolio.position('AAPL')
    
    if current_pos > 0:
        current_price = data.close
        
        # Initialize trailing stop
        if 'trailing_stop' not in state:
            state['trailing_stop'] = current_price * 0.90  # 10% below entry
            state['highest_price'] = current_price
        
        # Update highest price and trailing stop
        if current_price > state['highest_price']:
            state['highest_price'] = current_price
            # Trail stop 10% below highest price
            state['trailing_stop'] = current_price * 0.90
        
        # Exit if price hits trailing stop
        if current_price <= state['trailing_stop']:
            print(f"TRAILING STOP: {current_price} <= {state['trailing_stop']}")
            return {'symbol': 'AAPL', 'action': 'sell', 'quantity': 'all'}
    
    return None

Portfolio-Level Risk Controls

Maximum Portfolio Heat

python
def check_portfolio_risk(portfolio, max_heat=0.06):
    """Ensure total portfolio risk doesn't exceed limit"""
    
    total_risk = 0
    for symbol, position in portfolio.positions.items():
        if position > 0:
            # Calculate risk per position (simplified)
            position_value = position * get_current_price(symbol)
            position_risk = position_value * 0.05  # Assume 5% risk per position
            total_risk += position_risk
    
    heat_ratio = total_risk / portfolio.equity
    return heat_ratio <= max_heat

Correlation Limits

python
def check_correlation_limits(symbols, max_correlated_positions=3):
    """Limit positions in highly correlated assets"""
    
    # Simplified: Group by sector
    tech_stocks = ['AAPL', 'GOOGL', 'MSFT', 'TSLA']
    tech_positions = sum(1 for s in symbols if s in tech_stocks)
    
    return tech_positions <= max_correlated_positions

Common Risk Management Mistakes

❌ What NOT to Do

  1. Risking too much per trade (>5% of account)
  2. No stop losses or moving stops against you
  3. Position sizing without considering volatility
  4. Averaging down on losing positions
  5. Revenge trading after losses
  6. Ignoring correlation between positions

✅ Best Practices

  1. Risk 1-2% per trade maximum
  2. Set stops before entry and stick to them
  3. Size positions based on risk, not conviction
  4. Diversify across time and assets
  5. Take partial profits on winners
  6. Review and adjust risk parameters regularly

Risk Metrics to Track

python
def calculate_risk_metrics(trades, portfolio):
    """Calculate important risk metrics"""
    
    returns = [trade['return_pct'] for trade in trades]
    
    # Maximum Drawdown
    equity_curve = []
    running_equity = portfolio.initial_capital
    for ret in returns:
        running_equity *= (1 + ret / 100)
        equity_curve.append(running_equity)
    
    peak = equity_curve[0]
    max_drawdown = 0
    for equity in equity_curve:
        if equity > peak:
            peak = equity
        drawdown = (peak - equity) / peak
        max_drawdown = max(max_drawdown, drawdown)
    
    # Sharpe Ratio (simplified)
    avg_return = sum(returns) / len(returns)
    std_dev = (sum([(r - avg_return)**2 for r in returns]) / len(returns))**0.5
    sharpe_ratio = avg_return / std_dev if std_dev > 0 else 0
    
    # Win Rate
    wins = [r for r in returns if r > 0]
    win_rate = len(wins) / len(returns)
    
    return {
        'max_drawdown': max_drawdown,
        'sharpe_ratio': sharpe_ratio, 
        'win_rate': win_rate
    }

Implementation Example

python
def risk_managed_strategy(data_contexts, portfolio, state):
    """Complete example with risk management"""
    
    data = data_contexts['AAPL']
    
    # Risk parameters
    MAX_RISK_PER_TRADE = 0.02
    STOP_LOSS_PCT = 0.05
    MAX_PORTFOLIO_RISK = 0.10
    
    current_pos = portfolio.position('AAPL')
    
    # Entry logic
    if should_buy() and current_pos == 0:
        
        # Check portfolio-level risk first
        if not check_portfolio_risk(portfolio, MAX_PORTFOLIO_RISK):
            print("Portfolio risk limit reached")
            return None
        
        # Calculate position size
        entry_price = data.close
        stop_price = entry_price * (1 - STOP_LOSS_PCT)
        account_risk = portfolio.equity * MAX_RISK_PER_TRADE
        risk_per_share = entry_price - stop_price
        shares = int(account_risk / risk_per_share)
        
        # Ensure we have enough cash
        cost = shares * entry_price
        if cost <= portfolio.cash:
            state['stop_price'] = stop_price
            state['entry_price'] = entry_price
            
            return {'symbol': 'AAPL', 'action': 'buy', 'quantity': shares}
    
    # Exit logic (stop loss)
    elif current_pos > 0 and data.close <= state.get('stop_price', 0):
        return {'symbol': 'AAPL', 'action': 'sell', 'quantity': 'all'}
    
    return None

Remember: Risk management is not about avoiding all risks, but about taking calculated risks that can lead to long-term profitability.

Test your trading strategies risk-free with professional backtesting.