deploy: 2026-03-20 07:49
This commit is contained in:
59
risk/position_sizing.py
Normal file
59
risk/position_sizing.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""Position sizing utilities.
|
||||
|
||||
Provides various sizing methods beyond the basic risk-percentage approach.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class SizingMethod(str, Enum):
|
||||
FIXED_RISK = "fixed_risk"
|
||||
FIXED_AMOUNT = "fixed_amount"
|
||||
KELLY = "kelly"
|
||||
|
||||
|
||||
def fixed_risk_size(
|
||||
balance: float,
|
||||
entry_price: float,
|
||||
stop_loss: float,
|
||||
risk_pct: float = 0.02,
|
||||
) -> float:
|
||||
"""Position size = (balance * risk%) / |entry - SL|."""
|
||||
price_risk = abs(entry_price - stop_loss)
|
||||
if price_risk == 0:
|
||||
return 0.0
|
||||
return round((balance * risk_pct) / price_risk, 8)
|
||||
|
||||
|
||||
def fixed_amount_size(
|
||||
amount_usd: float,
|
||||
entry_price: float,
|
||||
) -> float:
|
||||
"""Fixed USD amount converted to asset quantity."""
|
||||
if entry_price <= 0:
|
||||
return 0.0
|
||||
return round(amount_usd / entry_price, 8)
|
||||
|
||||
|
||||
def kelly_size(
|
||||
win_rate: float,
|
||||
avg_win: float,
|
||||
avg_loss: float,
|
||||
balance: float,
|
||||
entry_price: float,
|
||||
fraction: float = 0.5,
|
||||
) -> float:
|
||||
"""Half-Kelly sizing for conservative edge exploitation.
|
||||
|
||||
Kelly% = W - (1-W)/R where R = avg_win/avg_loss
|
||||
We use fraction (default 0.5) of full Kelly for safety.
|
||||
"""
|
||||
if avg_loss == 0 or entry_price <= 0:
|
||||
return 0.0
|
||||
|
||||
r = avg_win / avg_loss
|
||||
kelly_pct = win_rate - (1 - win_rate) / r
|
||||
kelly_pct = max(0.0, min(kelly_pct * fraction, 0.1)) # cap at 10%
|
||||
return round((balance * kelly_pct) / entry_price, 8)
|
||||
Reference in New Issue
Block a user