Risk Management in Crypto Trading: Build a Python Position Sizer That Adapts to Volatility
Crypto markets move fast. A 10% Bitcoin drop can wipe a leveraged position in minutes. Traders chase signals but forget sizing: how much to risk per trade. Poor sizing kills accounts faster than bad entries.
This article shows a Python framework for dynamic position sizing. It uses volatility (ATR), account risk limits, and correlation adjustments. Run it on your data. Tie it to Market Masters AI screeners for live signals.
Why Sizing Matters More Than Predictions
90% of retail traders lose money, per broker data. Entries get attention, but exits and sizing decide survival.
Fixed dollar risk ($100/trade) ignores volatility. High vol assets need smaller positions. Python automates this.
Core Concepts
- Fixed Fractional Risk: Risk R% of account per trade. Position size = (account * R) / (stop_loss_distance)
- Volatility Scaling: Use ATR (Average True Range) for stop distance.
- Kelly Criterion: Optimal f = (win_prob * avg_win - loss_prob * avg_loss) / avg_win. Conservative: half-Kelly.
- Portfolio Correlation: Reduce size if assets correlate >0.7.
Python Implementation
import pandas as pd
import numpy as np
from typing import Dict, Tuple
class RiskSizer:
def __init__(self, account_size: float = 10000, risk_per_trade: float = 0.01):
self.account = account_size
self.risk_pct = risk_per_trade
def atr_stop_distance(self, prices: pd.Series, period: int = 14) -> float:
high_low = prices.max() - prices.min()
close_prev = prices.shift(1)
tr = np.maximum(high_low, np.maximum(abs(prices - close_prev), abs(close_prev - prices.shift(2))))
atr = tr.rolling(period).mean().iloc[-1]
return atr
def position_size(self, entry: float, stop_loss: float, atr: float, symbol: str) -> Dict:
raw_risk = abs(entry - stop_loss)
vol_adjusted_risk = max(raw_risk, 2 * atr)
dollar_risk = self.account * self.risk_pct
size = dollar_risk / vol_adjusted_risk
return {'symbol': symbol, 'size': size, 'dollar_risk': dollar_risk, 'stop_distance': vol_adjusted_risk}
prices = pd.Series([45000, 46000, 45500, 47000])
sizer = RiskSizer()
atr = sizer.atr_stop_distance(prices)
size = sizer.position_size(entry=46500, stop_loss=45000, atr=atr, symbol='BTC')
print(size)
Advanced: Kelly + Correlation
def kelly_fraction(win_rate: float, win_loss_ratio: float) -> float:
p = win_rate
b = win_loss_ratio
f = (p * (b + 1) - 1) / b
return max(0, f / 2) # Half Kelly
win_rate = 0.55
ratio = 1.8
kelly = kelly_fraction(win_rate, ratio)
print(f"Optimal risk: {kelly:.1%}")
Live Trading Integration
Load Binance data via ccxt:
import ccxt
exchange = ccxt.binance()
bars = exchange.fetch_ohlcv('BTC/USDT', '1h')
df = pd.DataFrame(bars, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
sizer = RiskSizer(account_size=50000)
atr = sizer.atr_stop_distance(df['close'])
# Signal from TA: RSI <30 buy
if rsi_latest < 30:
pos = sizer.position_size(df['close'].iloc[-1], df['close'].iloc[-1] * 0.95, atr, 'BTC/USDT')
print(f"Buy {pos['size']:.2f} BTC")
Market Masters Orion runs this logic across 2500+ coins. Get conviction scores, auto-suggest sizes, Telegram alerts.
Common Pitfalls
- Ignoring leverage: Size pre-leverage.
- Revenge trading: Cap daily risk at 5%.
- Drawdown rules: Pause if -20% monthly.
Wrapping Up
Sizing turns random entries into edge. Code above adapts to vol, correlations. Customize for your strategy.
Start free at marketmasters.ai. Screen signals, get Orion AI sizing. 30-day Premium trial, no card.
Top comments (0)