Мысли о высокочастотных торговых стратегиях (1)

Автор:Лидия., Создано: 2023-08-04 13:47:39, Обновлено: 2023-09-12 15:50:10

img

Мысли о высокочастотных торговых стратегиях (1)

Я написал две статьи о высокочастотной торговле цифровыми валютами, а именно:Стратегия высокочастотных цифровых валют Подробное введение и Заработать 80 раз за 5 дней, сила высокочастотной стратегии. Тем не менее, эти статьи можно рассматривать только как обмен опытом и предоставление общего обзора. На этот раз я планирую написать серию статей, чтобы представить мыслительный процесс, лежащий в основе высокочастотного трейдинга с нуля. Я надеюсь сохранить его кратким и ясным, но из-за моего ограниченного опыта мое понимание высокочастотного трейдинга может быть не очень глубоким. Эта статья должна рассматриваться как отправная точка для обсуждения, и я приветствую исправления и руководство от экспертов.

Источник высокочастотных прибылей

В своих предыдущих статьях я упоминал, что высокочастотные стратегии особенно подходят для рынков с чрезвычайно волатильными колебаниями. Изменения цены торгового инструмента в течение короткого периода времени состоят из общих тенденций и колебаний. Хотя это действительно выгодно, если мы можем точно предсказать изменения тренда, это также самый сложный аспект. В этой статье я в первую очередь сосредоточусь на высокочастотных стратегиях производителя и не буду углубляться в прогнозирование тренда. На колеблющихся рынках, путем размещения ордеров стратегически, если частота торгов достаточно высока, и маржа прибыли значительна, она может покрыть потенциальные убытки, вызванные тенденциями. Таким образом, прибыльность может быть достигнута без предсказания движений рынка. В настоящее время биржи предоставляют скидки на сделки производителей, которые также являются компонентом прибыли. Чем больше конкурентная составляющая рынка, тем выше должна быть доля скидок.

Проблемы, которые нужно решить

  1. Первая проблема в реализации стратегии, которая размещает как заказы на покупку, так и на продажу, заключается в определении места размещения этих заказов. Чем ближе заказы размещаются к глубине рынка, тем выше вероятность исполнения. Однако в очень волатильных рыночных условиях цена, по которой ордер мгновенно выполняется, может быть далеко от глубины рынка, что приводит к недостаточной прибыли. С другой стороны, размещение заказов слишком далеко снижает вероятность исполнения. Это проблема оптимизации, которую необходимо решить.

  2. Контроль позиций имеет решающее значение для управления рисками. Стратегия не может накапливать чрезмерные позиции в течение длительных периодов. Это может быть решено путем контроля расстояния и количества размещенных заказов, а также установления ограничений на общие позиции.

Для достижения вышеуказанных целей требуется моделирование и оценка для различных аспектов, таких как вероятность исполнения, прибыль от исполнения и оценка рынка. Существует множество статей и статей на эту тему, используя ключевые слова, такие как High-Frequency Trading и Orderbook. Многие рекомендации также можно найти в Интернете, хотя дальнейшая разработка выходит за рамки этой статьи. Кроме того, целесообразно установить надежную и быструю систему обратного тестирования.

Требуемые данные

Binance предоставляетзагружаемые данныедля отдельных сделок и лучших заказов bid/ask. Глубокие данные можно загрузить через их API, будучи включенными в белый список, или их можно собирать вручную. Для целей обратного тестирования достаточно агрегированных торговых данных. В этой статье мы будем использовать пример данных HOOKUSDT-aggTrades-2023-01-27.

В [1]:

from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

Отдельные данные о торговле включают следующее:

  1. agg_trade_id: идентификатор агрегированной сделки.
  2. цена: цена, по которой была выполнена сделка.
  3. Количество: количество торговли.
  4. first_trade_id: в случаях, когда несколько сделок агрегированы, это представляет собой идентификатор первой сделки.
  5. last_trade_id: идентификатор последней сделки в агрегации.
  6. transact_time: Время выполнения сделки.
  7. is_buyer_maker: указывает направление торговли. True представляет собой ордер на покупку, выполненный как производитель, в то время как ордер на продажу выполняется как покупатель.

Как видно, в тот день было совершено 660 000 сделок, что указывает на высокую активность рынка.

В [4]:

trades = pd.read_csv('COMPUSDT-aggTrades-2023-07-02.csv')
trades

Выход[4]: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.

img

664475 строк × 7 столбцов

Моделирование индивидуальной суммы торговли

Во-первых, данные обрабатываются путем разделения первоначальных сделок на две группы: заказы покупки, выполненные в качестве производителей, и заказы продажи, выполненные в качестве покупателей. Кроме того, первоначальные агрегированные торговые данные объединяют сделки, выполненные в одно и то же время, по одной цене и в одном направлении в одну точку данных. Например, если есть один ордер покупки с объемом 100, он может быть разделен на две сделки с объемом 60 и 40, соответственно, если цены разные. Это может повлиять на оценку объемов заказов покупки. Поэтому необходимо снова агрегировать данные на основе transact_time. После этой второй агрегации объем данных уменьшается на 140 000 записей.

В [6]:

trades['date'] = pd.to_datetime(trades['transact_time'], unit='ms')
trades.index = trades['date']
buy_trades = trades[trades['is_buyer_maker']==False].copy()
sell_trades = trades[trades['is_buyer_maker']==True].copy()
buy_trades = buy_trades.groupby('transact_time').agg({
    'agg_trade_id': 'last',
    'price': 'last',
    'quantity': 'sum',
    'first_trade_id': 'first',
    'last_trade_id': 'last',
    'is_buyer_maker': 'last',
    'date': 'last',
    'transact_time':'last'
})
sell_trades = sell_trades.groupby('transact_time').agg({
    'agg_trade_id': 'last',
    'price': 'last',
    'quantity': 'sum',
    'first_trade_id': 'first',
    'last_trade_id': 'last',
    'is_buyer_maker': 'last',
    'date': 'last',
    'transact_time':'last'
})
buy_trades['interval']=buy_trades['transact_time'] - buy_trades['transact_time'].shift()
sell_trades['interval']=sell_trades['transact_time'] - sell_trades['transact_time'].shift()

В [10]:

print(trades.shape[0] - (buy_trades.shape[0]+sell_trades.shape[0]))

Вне [10]: 146181

В качестве примера возьмем заказы на покупку, давайте сначала составим график гистограммы. Можно заметить, что существует значительный эффект длинного хвоста, причем большинство данных сосредоточено в сторону левой части гистограммы. Однако есть также несколько крупных сделок, распределенных в сторону конца хвоста.

В [36]:

buy_trades['quantity'].plot.hist(bins=200,figsize=(10, 5));

Вне [36]:

img

Для более легкого наблюдения, давайте подстрижем хвост и проанализируем данные.

В [37]:

buy_trades['quantity'][buy_trades['quantity']<200].plot.hist(bins=200,figsize=(10, 5));

Вне [37]:

img

Было проведено многочисленные исследования распределения объемов торговли. Было обнаружено, что объемы торговли следуют распределению по законам мощности, также известному как распределение Парето, которое является распространенным распределением вероятности в статистической физике и социальных науках. В распределении по законам мощности вероятность размера (или частоты) события пропорциональна отрицательному экспоненту размера этого события. Основной характеристикой этого распределения является то, что частота крупных событий (т.е. далеких от среднего) выше, чем ожидается во многих других распределениях. Это именно характеристика распределения объемов торговли. Форма распределения Парето дана формулой P ((x) = C ((x^-α). Давайте проверим это эмпирически.

На следующем графике представлена вероятность того, что сумма торговли превысит определенное значение. Синяя линия представляет фактическую вероятность, а оранжевая линия представляет симулируемую вероятность. Обратите внимание, что мы не будем вдаваться в конкретные параметры в данный момент. Можно заметить, что распределение действительно следует распределению Парето. Поскольку вероятность того, что сумма торговли превышает нуль, равна 1, и для удовлетворения нормализации, уравнение распределения должно быть следующим:

img

Здесь N является параметром для нормализации. Мы выберем средний объем торговли, M, и установим альфу на -2.06. Конкретную оценку альфы можно получить, рассчитав P-значение, когда D=N. В частности, альфа = log (((P(d>M)) /log ((2). Выбор разных точек может привести к незначительным различиям в значении альфы.

В [55]:

depths = range(0, 250, 2)
probabilities = np.array([np.mean(buy_trades['quantity'] > depth) for depth in depths])
alpha = np.log(np.mean(buy_trades['quantity'] > mean_quantity))/np.log(2)
mean_quantity = buy_trades['quantity'].mean()
probabilities_s = np.array([(1+depth/mean_quantity)**alpha for depth in depths])

plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities)
plt.plot(depths, probabilities_s)
plt.xlabel('Depth')
plt.ylabel('Probability of execution')
plt.title('Execution probability at different depths')
plt.grid(True)

Выход[55]:

img

В [56]:

plt.figure(figsize=(10, 5))
plt.grid(True)
plt.title('Diff')
plt.plot(depths, probabilities_s-probabilities);

Выход[56]:

img

Однако эта оценка является только приблизительной, как показано на графике, где мы изображаем разницу между моделируемыми и фактическими значениями. Когда сумма торговли невелика, отклонение значительно, даже приближается к 10%. Хотя выбор разных точек во время оценки параметров может улучшить точность вероятности этой конкретной точки, он не решает проблему отклонения в целом. Это расхождение возникает из-за разницы между распределением закона мощности и фактическим распределением. Чтобы получить более точные результаты, уравнение распределения закона мощности необходимо изменить.

img

Чтобы упростить, давайте используем r = q / M для представления нормализованной суммы торговли. Мы можем оценить параметры, используя тот же метод, что и раньше. Следующий график показывает, что после модификации максимальное отклонение не более 2%. Теоретически можно сделать дальнейшие корректировки, но этот уровень точности уже достаточен.

В [52]:

depths = range(0, 250, 2)
probabilities = np.array([np.mean(buy_trades['quantity'] > depth) for depth in depths])
mean = buy_trades['quantity'].mean()
alpha = np.log(np.mean(buy_trades['quantity'] > mean))/np.log(2.05)
probabilities_s = np.array([(((1+20**(-depth/mean))*depth+mean)/mean)**alpha for depth in depths])

plt.figure(figsize=(10, 5))
plt.plot(depths, probabilities)
plt.plot(depths, probabilities_s)
plt.xlabel('Depth')
plt.ylabel('Probability of execution')
plt.title('Execution probability at different depths')
plt.grid(True)

Выход[52]:

img

В [53]:

plt.figure(figsize=(10, 5))
plt.grid(True)
plt.title('Diff')
plt.plot(depths, probabilities_s-probabilities);

Выход[53]:

img

При расчетном уравнении для распределения объема торговли важно отметить, что вероятности в уравнении - это не фактические вероятности, а условные вероятности.

На данный момент текст уже довольно длинный, и остается много вопросов, на которые необходимо ответить.


Больше