DEV Community

Market Masters
Market Masters

Posted on

Risk Management in Crypto Trading: Build a Python Position Sizer That Adapts to Volatility

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

  1. Fixed Fractional Risk: Risk R% of account per trade. Position size = (account * R) / (stop_loss_distance)
  2. Volatility Scaling: Use ATR (Average True Range) for stop distance.
  3. Kelly Criterion: Optimal f = (win_prob * avg_win - loss_prob * avg_loss) / avg_win. Conservative: half-Kelly.
  4. 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)
Enter fullscreen mode Exit fullscreen mode

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%}")
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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)