Разработка AI-системы расчёта оптимального размера позиции
Position sizing определяет, сколько капитала вложить в каждую сделку. Это не менее важно, чем качество торговых сигналов: даже хорошая стратегия разрушится при слишком агрессивном sizing, и заработает меньше потенциального при слишком консервативном. AI-система адаптирует размер позиции к текущим условиям рынка и уверенности сигнала.
Классические методы sizing
Fixed fractional (фиксированный процент):
Position_Size = Account_Size × f
Простейший подход. f = 1-2% риска на сделку — стандарт для retail. Не адаптируется к качеству сигнала.
Kelly Criterion:
def kelly_fraction(win_rate, win_loss_ratio):
"""
f* = W - (1-W)/R
W: вероятность выигрыша, R: среднее_выигрыш / среднее_проигрыш
"""
return win_rate - (1 - win_rate) / win_loss_ratio
kelly_f = kelly_fraction(win_rate=0.55, win_loss_ratio=2.0)
# kelly_f = 0.55 - 0.45/2.0 = 0.325 (32.5% капитала!)
# Это полный Келли — слишком агрессивно
half_kelly = kelly_f * 0.5 # Практика: 25-50% от Kelly
Проблема Kelly: требует точных оценок win rate и R. Ошибка в оценке → overbet → ускоренное разорение (growth-optimal отличается от risk-pertain trade-offs).
ML для dynamic position sizing
Confidence-adjusted sizing: Размер позиции пропорционален уверенности ML-сигнала:
def ml_position_size(model_proba, base_size, min_prob=0.55, max_prob=0.80):
"""
При probability 0.55 → base_size × 0.5 (минимум)
При probability 0.80 → base_size × 2.0 (максимум)
"""
if model_proba < min_prob:
return 0 # не торгуем
scale = (model_proba - min_prob) / (max_prob - min_prob)
return base_size * (0.5 + 1.5 * min(scale, 1.0))
Volatility-adjusted sizing: Нормализация размера позиции на волатильность инструмента:
def vol_normalized_size(target_risk_pct, price, volatility_daily, account_size):
"""
Размер позиции: такой, чтобы 1σ дневное движение = target_risk_pct капитала
"""
dollar_risk = account_size * target_risk_pct
position_value = dollar_risk / volatility_daily
n_shares = position_value / price
return n_shares
ATR (Average True Range) как proxy волатильности: чем выше ATR, тем меньше лот.
RL для adaptive sizing
RL-агент учится оптимальному sizing в зависимости от контекста:
Состояние агента:
- Уверенность ML-сигнала (probability score)
- Текущая волатильность (ATR/10-day realized vol)
- Drawdown от пика (если уже в просадке — меньше риска)
- Macro regime (expansion vs. contraction)
- Portfolio correlation: если позиция сильно коррелирует с уже открытыми — уменьшить
Действия: дискретное пространство [0%, 0.5%, 1%, 1.5%, 2%, 3%] риска на сделку.
Награда:
Reward = PnL / max_drawdown_penalty
Агент учится не только максимизировать return, но и ограничивать drawdown.
Risk Parity Sizing для портфеля
При одновременном управлении несколькими позициями:
def risk_parity_position_sizes(signals, volatilities, correlations, target_portfolio_vol):
"""
Размеры позиций такие, чтобы каждая вносила равный вклад в риск портфеля
"""
n = len(signals)
w = np.ones(n) / n # начальное равное распределение
for _ in range(100): # итеративная оптимизация
cov = np.diag(volatilities) @ correlations @ np.diag(volatilities)
portfolio_vol = np.sqrt(w @ cov @ w)
marginal_risk = cov @ w / portfolio_vol
risk_contributions = w * marginal_risk
# Скорректировать в сторону равного вклада
w = w * (1 / risk_contributions)
w = w / w.sum() # нормировать
# Масштабировать для целевой волатильности
portfolio_vol = np.sqrt(w @ cov @ w) * np.sqrt(252)
w = w * (target_portfolio_vol / portfolio_vol)
return w
Drawdown-adjusted sizing (Anti-Martingale)
При росте портфеля — увеличивать риск (compound growth). При просадке — снижать:
def drawdown_adjusted_size(base_risk, current_equity, peak_equity, max_drawdown=0.20):
"""
При drawdown > max_drawdown: полная остановка торговли
При drawdown 0-10%: линейное снижение риска
"""
drawdown = (peak_equity - current_equity) / peak_equity
if drawdown > max_drawdown:
return 0 # circuit breaker
reduction_factor = 1 - (drawdown / max_drawdown)
return base_risk * reduction_factor
Симуляция и оценка sizing стратегий
# Сравнение различных подходов
strategies = {
'fixed_1pct': lambda signal, vol, eq: fixed_fractional(1.0),
'fixed_kelly': lambda signal, vol, eq: half_kelly_sizing(signal),
'vol_normalized': lambda signal, vol, eq: vol_normalized(vol, target_risk=1.0),
'ml_adaptive': lambda signal, vol, eq: ml_size(signal.probability, vol, eq.drawdown),
}
for name, size_fn in strategies.items():
equity_curve = simulate_strategy(trades, size_fn)
print(f"{name}: Sharpe={sharpe(equity_curve):.2f}, MaxDD={max_drawdown(equity_curve):.1%}")
Monte Carlo симуляция 10,000 путей для каждого sizing метода — сравнение distribution результатов.
Типичный результат: ML adaptive sizing улучшает Sharpe на 15-30% и снижает max drawdown на 20-40% vs. fixed fractional при той же стратегии входов.
Сроки: volatility-adjusted sizing + drawdown adjustment — 2-3 недели. RL adaptive sizing с risk parity и full simulation — 6-8 недель.







