Position Sizing¶
qlcore provides multiple position sizing strategies to manage risk and optimize capital allocation.
Fixed Sizing¶
Fixed Quantity¶
Trade a fixed number of units:
import qlcore as qc
from decimal import Decimal
size = qc.fixed_quantity(quantity="0.1")
print(f"Size: {size}") # 0.1
Fixed Notional¶
Trade a fixed dollar amount:
size = qc.fixed_notional(
notional="5000", # $5000
price="45000", # BTC price
)
print(f"Size: {size}") # 0.111... BTC
Percentage-Based Sizing¶
Percent of Equity¶
Allocate a percentage of account equity:
size = qc.percent_of_equity(
equity=10000, # Account equity
percent="0.1", # 10% of equity
price="45000", # Entry price
)
print(f"Size: {size}") # ~0.022 BTC ($1000 notional)
Common Allocations
- Conservative: 2-5% per position
- Moderate: 5-10% per position
- Aggressive: 10-20% per position
Risk-Based Sizing¶
Risk Per Trade¶
Size position based on maximum acceptable loss:
size = qc.risk_per_trade(
equity=10000,
risk_percent="0.02", # Risk 2% of equity
entry_price="45000",
stop_price="44000", # Stop loss price
)
print(f"Size: {size}") # Position sized so $1000 stop = 2% loss
The formula: size = (equity × risk%) / (entry - stop)
Example breakdown:
- Equity: $10,000
- Risk: 2% = $200 max loss
- Stop distance: $45,000 - $44,000 = $1,000
- Size: $200 / $1,000 = 0.2 BTC
With Leverage¶
For leveraged positions, account for margin:
size = qc.risk_per_trade(
equity=10000,
risk_percent="0.02",
entry_price="45000",
stop_price="44000",
leverage=10, # Optional leverage factor
)
Volatility-Based Sizing¶
ATR Position Size¶
Size based on Average True Range (volatility):
size = qc.atr_position_size(
equity=10000,
risk_percent="0.02", # 2% risk
atr="1500", # Current ATR in price units
atr_multiplier=2, # Stop at 2x ATR
)
print(f"Size: {size}")
The formula: size = (equity × risk%) / (ATR × multiplier)
Example:
- ATR = $1,500
- Stop = 2 × ATR = $3,000
- Size = $200 / $3,000 = 0.067 BTC
Kelly Criterion¶
Kelly Fraction¶
Optimal bet size based on win rate and payoff:
kelly = qc.kelly_fraction(
win_rate=0.55, # 55% win rate
avg_win=100, # Average winning trade
avg_loss=80, # Average losing trade
)
print(f"Kelly: {kelly:.2%}") # Optimal fraction of capital
Full Kelly is Aggressive
Most practitioners use fractional Kelly (e.g., half-Kelly) to reduce volatility:
Example calculation:
# Win rate: 55%, Avg win: $100, Avg loss: $80
# Edge = 0.55 × 100 - 0.45 × 80 = 55 - 36 = 19
# Kelly = Edge / Avg Win = 19 / 100 = 0.19 (19%)
kelly = qc.kelly_fraction(0.55, 100, 80)
print(f"Full Kelly: {kelly:.1%}") # 19%
print(f"Half Kelly: {kelly*0.5:.1%}") # 9.5%
Position Limits¶
Apply Constraints¶
Ensure positions respect limits:
size = qc.apply_position_limits(
desired_size=Decimal("1.0"),
max_position_size=Decimal("0.5"), # Max allowed
min_position_size=Decimal("0.01"), # Min allowed
lot_size=Decimal("0.001"), # Round to lot size
)
print(f"Constrained size: {size}") # 0.5 (capped at max)
Multiple Constraints¶
from decimal import Decimal
desired = Decimal("0.1")
# Check max position
if desired > max_position:
desired = max_position
# Check max notional
notional = desired * price
if notional > max_notional:
desired = max_notional / price
# Round to lot size
size = qc.apply_position_limits(
desired_size=desired,
lot_size=Decimal("0.001"),
)
Complete Sizing Example¶
import qlcore as qc
from decimal import Decimal
# Account state
equity = Decimal("10000")
price = Decimal("45000")
stop = Decimal("43500")
atr = Decimal("1200")
# Calculate sizes using different methods
sizes = {
"Fixed 10%": qc.percent_of_equity(equity, "0.10", price),
"2% Risk": qc.risk_per_trade(equity, "0.02", price, stop),
"ATR 2x": qc.atr_position_size(equity, "0.02", atr, 2),
}
print("Position Sizing Comparison")
print("-" * 40)
for method, size in sizes.items():
notional = size * price
print(f"{method:15} {size:.6f} BTC (${notional:.0f})")
Output:
Position Sizing Comparison
----------------------------------------
Fixed 10% 0.022222 BTC ($1000)
2% Risk 0.133333 BTC ($6000)
ATR 2x 0.083333 BTC ($3750)
Using Namespace¶
import qlcore as qc
qc.sizing.fixed_quantity("0.1")
qc.sizing.fixed_notional("5000", "45000")
qc.sizing.percent_of_equity(10000, "0.1", "45000")
qc.sizing.risk_per_trade(10000, "0.02", "45000", "44000")
qc.sizing.atr_position_size(10000, "0.02", "1500", 2)
qc.sizing.kelly_fraction(0.55, 100, 80)
qc.sizing.apply_position_limits(size, max_size, min_size, lot_size)