Kelly Criterion Position Sizing in Volatile Crypto Markets
Abstract
Position sizing is often the most neglected aspect of trading system design, yet it determines 70-80% of long-term returns. This paper presents our implementation of fractional Kelly Criterion with dynamic volatility and confidence scaling, demonstrating superior risk-adjusted performance in crypto market backtests.
The Kelly Criterion
The Kelly Criterion, developed by John L. Kelly Jr. at Bell Labs in 1956, provides a mathematically optimal bet sizing formula:
Where:
- = optimal fraction of capital to bet
- = probability of winning
- = probability of losing
- = ratio of net profit on a win to net loss on a loss
For symmetric payoffs (win/loss ratio of 1):
Example Calculation
Given:
- Win rate: 55% (, )
- Win/loss ratio: 1:1 ()
Full Kelly:
Why Full Kelly Is Dangerous
While mathematically optimal for maximizing long-term growth, full Kelly has severe practical problems:
1. Volatility of Returns
Full Kelly produces extremely volatile equity curves. A 10-trade losing streak (which happens approximately once every 2,000 trades at 55% win rate) can draw down 65% of capital.
The probability of consecutive losses is:
For and :
2. Parameter Uncertainty
The formula assumes perfect knowledge of win rate and payoff ratio. In reality, these are estimated from historical data and change over time.
3. Correlation Effects
Kelly assumes independent bets. In trading, positions are often correlated, effectively increasing risk.
4. Psychological Tolerance
Few traders can stomach the drawdowns that full Kelly produces without abandoning their system.
Our Implementation: Fractional Kelly
We use fractional Kelly (0.25-0.5) with dynamic adjustments:
pythondef calculate_position_size( account_value: float, win_rate: float, signal_confidence: float, current_volatility: float, baseline_volatility: float, current_drawdown: float, correlation_factor: float ) -> float: """ Calculate position size using fractional Kelly with adjustments. """ # Base Kelly calculation kelly = (2 * win_rate - 1) # Apply fractional Kelly (0.25 by default) base_size = account_value * kelly * 0.25 # Volatility scaling: reduce in high vol, increase in low vol vol_multiplier = baseline_volatility / current_volatility vol_multiplier = min(max(vol_multiplier, 0.5), 1.5) # Cap at 0.5x-1.5x # Confidence scaling: linear with signal confidence confidence_multiplier = signal_confidence # Drawdown throttling if current_drawdown > 0.15: drawdown_multiplier = 0.5 elif current_drawdown > 0.10: drawdown_multiplier = 0.75 else: drawdown_multiplier = 1.0 # Correlation adjustment correlation_multiplier = 1.0 - (correlation_factor * 0.3) # Final position size position_size = ( base_size * vol_multiplier * confidence_multiplier * drawdown_multiplier * correlation_multiplier ) # Apply absolute limits max_position = account_value * 0.10 # Never exceed 10% min_position = account_value * 0.01 # Minimum meaningful position return max(min(position_size, max_position), min_position)
Adjustments Explained
Volatility Scaling
In high volatility periods, we reduce position size proportionally:
| Current Vol / Baseline Vol | Multiplier |
|---|---|
| > 2.0 | 0.50 |
| 1.5 - 2.0 | 0.67 |
| 1.0 - 1.5 | 0.80 |
| 0.5 - 1.0 | 1.20 |
| < 0.5 | 1.50 |
Confidence Scaling
Signal confidence (from our ML models) directly scales position:
- 90%+ confidence: Full calculated position
- 70-90%: 70-90% of calculated position
- 50-70%: 50-70% of calculated position
- < 50%: No trade
Drawdown Throttling
When underwater, we systematically reduce exposure:
- 0-10% drawdown: No adjustment
- 10-15% drawdown: 25% reduction
- 15-20% drawdown: 50% reduction
-
20%: Flatten all positions
Correlation Adjustment
High correlation between positions indicates concentrated risk:
- Correlation < 0.3: No adjustment
- Correlation 0.3-0.5: 5-15% reduction
- Correlation 0.5-0.7: 15-21% reduction
- Correlation > 0.7: 21-30% reduction
Backtesting Results
We tested three approaches over 3 years of crypto market data:
| Approach | CAGR | Max DD | Sharpe | Calmar |
|---|---|---|---|---|
| Full Kelly | 142% | 58% | 1.1 | 2.4 |
| Half Kelly | 98% | 34% | 1.8 | 2.9 |
| Our Fractional (0.25) | 72% | 21% | 2.4 | 3.4 |
Key observations:
- Full Kelly maximizes returns but with unacceptable drawdowns
- Half Kelly is a common compromise
- Our approach sacrifices some return for dramatically better risk-adjusted performance
Real-World Considerations
Transaction Costs
Position sizing must account for costs:
python# If expected edge is small, reduce position size expected_return = win_rate * avg_win - (1 - win_rate) * avg_loss cost_adjusted_return = expected_return - total_transaction_cost if cost_adjusted_return < min_expected_return: position_size = 0 # Skip trade
Liquidity Constraints
Large positions require scaling:
pythonmax_daily_volume_participation = 0.01 # 1% of daily volume liquidity_constrained_size = daily_volume * max_daily_volume_participation position_size = min(position_size, liquidity_constrained_size)
Margin Requirements
For leveraged positions:
pythonmax_leverage = 3.0 # Platform limit available_margin = account_value / max_leverage position_size = min(position_size, available_margin)
Conclusion
Position sizing is not glamorous, but it's essential. Our fractional Kelly implementation with dynamic adjustments provides:
- Mathematical foundation: Based on proven optimal growth theory
- Practical adjustments: Accounts for real-world constraints
- Risk management: Built-in drawdown throttling and correlation awareness
- Adaptability: Responds to changing market conditions
The result is a position sizing system that maximizes risk-adjusted returns while maintaining the drawdown profile necessary for long-term survival.
For more on our risk management approach, see our blog post on risk-first trading.