Разработка алгоритма VWAP (Volume-Weighted Average Price)
VWAP execution алгоритм — более умная версия TWAP: вместо равномерного распределения по времени, объём распределяется пропорционально историческому торговому объёму. В часы высокой активности размещается больше ордеров, в тихие периоды — меньше. Цель — исполнить ордер по цене, близкой к рыночному VWAP за период.
Отличие VWAP от TWAP
TWAP делит объём равномерно по времени. VWAP делит объём пропорционально типичному рыночному объёму в каждый временной интервал.
Пример для BTC/USDT (24-часовая сессия): объём в 14:00–16:00 UTC (перекрытие европейской и американской сессий) значительно выше, чем в 02:00–04:00 UTC (минимальная активность). VWAP алгоритм учитывает это.
Предсказание объёмного профиля
def build_volume_profile_intraday(historical_df, n_buckets=48):
"""
Строим средний объём для каждого 30-минутного интервала дня
на основе исторических данных (последние 30 дней)
"""
historical_df['time_bucket'] = historical_df.index.time
avg_volume = historical_df.groupby('time_bucket')['volume'].mean()
# Нормализуем к единице (веса должны суммироваться в 1)
weights = avg_volume / avg_volume.sum()
return weights
Алгоритм исполнения
class VWAPExecutor:
def __init__(self, symbol, total_qty, duration_hours, exchange):
self.total_qty = total_qty
self.volume_weights = self.load_volume_profile(symbol, duration_hours)
# slice_sizes[i] = qty для i-го интервала
self.slice_sizes = [w * total_qty for w in self.volume_weights]
async def execute_interval(self, interval_idx):
target_qty = self.slice_sizes[interval_idx]
# Адаптируем если объём за прошлые интервалы отличался от прогноза
actual_volume = await self.get_market_volume(interval_idx)
expected_volume = self.expected_volumes[interval_idx]
if actual_volume > expected_volume * 1.5:
# Рынок активнее — увеличиваем ордер
target_qty *= (actual_volume / expected_volume)
await self.place_order(target_qty)
Участие в рыночном объёме (POV)
Participation Rate — альтернативный подход: исполнять X% от текущего рыночного объёма.
target_qty_per_interval = market_volume × participation_rate (например, 10%)
POV гарантирует минимальное рыночное влияние (не более 10% рынка), но не гарантирует исполнение к дедлайну при низком объёме.
Адаптация в реальном времени
Если текущее исполнение отстаёт от плана (рынок движется в неблагоприятную сторону) — алгоритм может:
- Агрессивнее исполнять оставшийся объём
- Временно перейти на market orders
- Расширить временной горизонт (если допустимо)
Benchmark и отчётность
| Метрика | Описание |
|---|---|
| Implementation Shortfall | Разница между решением торговать и финальным исполнением |
| VWAP Slippage | Average fill price vs рыночный VWAP |
| Market Impact | Насколько наши ордера двигали рынок |
| Fill Rate | % исполненного объёма |
Полный execution report после завершения: timeline исполнения, средняя цена fill vs VWAP, slippage по каждому интервалу.
Стек: Python (asyncio + CCXT), PostgreSQL для execution logs, Grafana для visualisation прогресса исполнения в реальном времени.







