Appearance
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
- Risking too much per trade (>5% of account)
- No stop losses or moving stops against you
- Position sizing without considering volatility
- Averaging down on losing positions
- Revenge trading after losses
- Ignoring correlation between positions
✅ Best Practices
- Risk 1-2% per trade maximum
- Set stops before entry and stick to them
- Size positions based on risk, not conviction
- Diversify across time and assets
- Take partial profits on winners
- 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.