Risk Management in Algo Trading: Python Code That Saves Your Capital
Retail traders lose money because they treat risk like an afterthought. In algorithmic trading, that's fatal. A single bad position can wipe out months of gains if you skip position sizing or drawdown controls. This article cuts through the theory: here's how to code risk management in Python that works across crypto and stocks.
Market Masters AI users see this daily. Orion, our AI assistant, flags setups with conviction scores from -100 to +100 based on 15 indicators. But even perfect signals fail without risk rules. Let's build them.
Position Sizing: Bet What You Can Afford to Lose
Fixed fractional sizing keeps risk constant per trade. Risk 1% of capital per position. Formula: shares = (capital * risk_percent) / stop_distance.
def position_size(capital, risk_pct, entry_price, stop_price):
risk_per_share = abs(entry_price - stop_price)
if risk_per_share == 0:
return 0
return int((capital * risk_pct) / risk_per_share)
# Example: $10k account, risk 1%, BTC entry $60k, stop $58k
size = position_size(10000, 0.01, 60000, 58000)
print(f"Buy {size} units") # Outputs: Buy 1
Kelly criterion optimizes for growth but halves for safety: f = (win_prob * win_loss_ratio - loss_prob) / win_loss_ratio.
def kelly_fraction(win_prob, avg_win, avg_loss):
return (win_prob * avg_win - (1 - win_prob) * avg_loss) / avg_win * 0.5 # Half Kelly
# 55% win rate, 1.5:1 reward:risk
f = kelly_fraction(0.55, 1.5, 1)
print(f"Kelly fraction: {f:.2%}") # ~15%, but use 0.5-1%
Integrate with live data. Pull from Market Masters API:
import requests
# Fetch latest BTC price and signals
response = requests.get('https://api.marketmasters.ai/signals/btc')
signal = response.json()
entry = signal['entry']
stop = signal['stop']
size = position_size(10000, 0.01, entry, stop)
Stop Losses: Volatility-Adjusted, Not Arbitrary
Fixed stops ignore volatility. Use ATR (Average True Range) for dynamic stops.
import pandas as pd
import numpy as np
def atr(highs, lows, closes, period=14):
tr1 = highs - lows
tr2 = abs(highs - closes.shift())
tr3 = abs(lows - closes.shift())
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
return tr.rolling(period).mean()
# Sample data
data = pd.DataFrame({'high': [60500, 61000], 'low': [59500, 60000], 'close': [60000, 60500]})
stop_distance = 2 * atr(data['high'], data['low'], data['close']).iloc[-1]
stop_price = entry_price - stop_distance
Trailing stops lock profits:
def trailing_stop(prices, atr_value, multiplier=3):
trail = prices[0]
for price in prices[1:]:
trail = max(trail + atr_value * 0.1, price - multiplier * atr_value)
return trail
Portfolio-Level Controls: Correlation and VaR
Single-asset risk is table stakes. Track portfolio beta and Value at Risk (VaR).
Historical VaR (95%):
def var_historical(returns, confidence=0.95):
return np.percentile(returns, (1 - confidence) * 100)
portfolio_returns = np.random.normal(0.001, 0.02, 1000) # Simulated
var_95 = var_historical(portfolio_returns)
print(f"95% VaR: {var_95:.2%} daily loss") # e.g., -4.2%
If VaR exceeds 2% of capital, pause trading.
Correlation matrix prevents crowded bets:
corr_matrix = pd.DataFrame(returns).corr()
if corr_matrix.loc['BTC', 'ETH'] > 0.8:
print("Reduce exposure: high correlation")
Market Masters screens 2500+ cryptos and S&P500 for low-correlation setups.
Drawdown Limits: The Kill Switch
Max drawdown 10%. Track equity curve.
def max_drawdown(equity_curve):
peak = equity_curve.cummax()
drawdown = (equity_curve - peak) / peak
return drawdown.min()
equity = pd.Series([10000, 10500, 9800, 10200])
dd = max_drawdown(equity)
if dd < -0.10:
print("Halt trading")
Full Example: Risk-Managed BTC Bot
import ccxt # For exchange API
exchange = ccxt.binance({'apiKey': 'YOUR_KEY'})
def risk_managed_trade(symbol='BTC/USDT', capital=10000):
ticker = exchange.fetch_ticker(symbol)
entry = ticker['last']
# Fetch OHLCV for ATR
ohlcv = exchange.fetch_ohlcv(symbol, '1h', limit=100)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
atr_val = atr(df['high'], df['low'], df['close']).iloc[-1]
stop = entry - 2 * atr_val
size = position_size(capital, 0.01, entry, stop)
if size > 0:
order = exchange.create_market_buy_order(symbol, size)
print(f"Bought {size} @ {entry}, stop {stop}")
return order
risk_managed_trade()
Test in paper trading first. Market Masters offers $10k simulated capital with 125x leverage.
Common Pitfalls
- Revenge trading after losses: enforce cooldowns.
- Leverage creep: cap at 5x for beginners.
- Ignoring slippage: add 0.1% buffer.
Try It Yourself
Code these rules into your next bot. For real-time signals and screeners, start with Market Masters AI free tier at marketmasters.ai. No credit card, instant access to Orion AI.
Word count: ~1050
Top comments (0)