Разработка AI-системы ребалансировки портфеля
Ребалансировка — возврат портфеля к целевым весам после дрейфа. Простейшая стратегия: раз в квартал продать выросшее, купить упавшее. AI-подход оптимизирует момент, частоту и метод ребалансировки с учётом транзакционных издержек и налоговых последствий.
Почему момент ребалансировки важен
Calendar rebalancing (раз в месяц/квартал) — игнорирует рыночные условия:
- В растущем рынке постоянно продаёт выросшие активы → drag
- В volatile рынке может ребалансироваться перед разворотом
Threshold rebalancing (при отклонении > N%): лучше, но всё ещё статическое правило.
Smart rebalancing:
- Учитывает transaction costs: не ребалансировать, если TC > ожидаемой пользы
- Использует market timing сигнал: откладывает ребалансировку при сильном тренде
- Налоговая оптимизация: предпочитает продавать убыточные позиции (tax-loss harvesting)
Формализация задачи
Стоимость отклонения от целевых весов:
def drift_cost(current_weights, target_weights, penalty=0.5):
"""
Tracking error due to drift: annualized vol × drift_magnitude
"""
drift = current_weights - target_weights
drift_variance = drift @ cov_matrix @ drift
return np.sqrt(drift_variance * 252)
Стоимость ребалансировки:
def rebalancing_cost(current_weights, new_weights, portfolio_value, tc=0.001):
trades = np.abs(new_weights - current_weights)
return trades.sum() * portfolio_value * tc
Оптимальная ребалансировка: минимизировать drift_cost + rebalancing_cost + tax_cost.
AI-алгоритм optimal rebalancing
Стохастическое управление (непрерывное время): Оптимальная "no-trade zone" — диапазон весов, в котором не ребалансируют из-за TC. Решение дифференциального уравнения (Almgren, 2005).
RL для ребалансировки:
# State: current_weights, target_weights, market_conditions
# Actions: [partial rebalance 50%, full rebalance, no action]
# Reward: -drift_cost - tc_cost + return_capture
class RebalancingEnv(gym.Env):
def step(self, action):
if action == 2: # full rebalance
cost = rebalancing_cost(self.weights, self.targets)
self.weights = self.targets.copy()
elif action == 1: # partial rebalance
self.weights = 0.5 * self.weights + 0.5 * self.targets
cost = rebalancing_cost(self.weights, self.targets) * 0.5
else: # no action
cost = 0
self.weights = apply_market_returns(self.weights)
reward = portfolio_return - cost - drift_penalty(self.weights, self.targets)
return self.state, reward, done, {}
Tax-Loss Harvesting
Ключевая возможность для налогооблагаемых счетов:
Принцип: продавать позиции с убытком для фиксации tax loss, одновременно заменяя на коррелированный актив (избегая wash-sale rule в США — 30-дневное ограничение).
def tax_loss_harvesting(portfolio, tax_rate=0.20, wash_sale_window=30):
"""
Идентифицируем позиции с нереализованными убытками.
Если tax_savings > transaction_costs → harvest.
Заменяем на коррелированный актив из списка substitutes.
"""
harvest_candidates = []
for ticker, position in portfolio.items():
unrealized_loss = position.unrealized_pnl
if unrealized_loss < 0:
tax_benefit = abs(unrealized_loss) * tax_rate
tc = abs(unrealized_loss) * 0.001 # 10 bps TC
if tax_benefit > tc:
harvest_candidates.append({
'ticker': ticker,
'net_benefit': tax_benefit - tc,
'substitute': find_substitute(ticker)
})
return harvest_candidates
Backtesting показывает: автоматический tax-loss harvesting добавляет 0.5-1.5% after-tax returns ежегодно.
Drift Monitoring и триггеры
Continuous monitoring:
def check_rebalance_triggers(current_weights, target_weights, thresholds):
drift = np.abs(current_weights - target_weights)
# Threshold triggers
if drift.max() > thresholds['single_asset']: # e.g., 5%
return 'REBALANCE_PARTIAL'
if (current_weights / target_weights).max() > thresholds['concentration']: # e.g., 1.5×
return 'REBALANCE_FULL'
# Correlation breakdown trigger (crisis detection)
if regime == 'crisis' and drift.sum() > thresholds['crisis_drift']:
return 'REBALANCE_IMMEDIATE'
return 'NO_ACTION'
Алерты:
- Ежедневная проверка весов → если дрейф > 3% → warning
- Еженедельный отчёт: текущие vs. целевые веса, рекомендации
- Автоматическое исполнение при превышении critical threshold (настраивается)
Интеграция с брокером
Prime broker / custody:
- Interactive Brokers API: FIX protocol + REST API для реальных ордеров
- Alpaca: REST API, доступен для автоматической торговли
- Saxo Bank / Dukascopy: FIX + REST для институциональных клиентов
Workflow:
- Расчёт текущих весов (рыночная стоимость каждой позиции / NAV)
- AI-решение: ребалансировать или нет
- Расчёт ордеров (net difference, round-lot)
- Отправка ордеров через брокерский API
- Подтверждение исполнения, обновление book
Сроки: threshold-based ребалансировка с TC-optimizing — 2-3 недели. RL-агент с tax harvesting и broker integration — 8-12 недель.







