В предыдущей статье продемонстрирована необходимость динамической корректировки параметров и оценки качества оценок путем изучения интервалов поступления заказов.
Binance предоставляет исторические загрузки данных для best_bid_price (наивысшая цена покупки), best_bid_quantity (количество по лучшей цене предложения), best_ask_price (наименьшая цена продажи), best_ask_quantity (количество по лучшей цене предложения) и transaction_time. Эти данные не включают второй или более глубокий уровень книги заказов. Анализ в этой статье основан на рынке YGG 7 августа, который испытал значительную волатильность с более чем 9 миллионами точек данных.
Во-первых, давайте посмотрим на рыночные условия в тот день. Были большие колебания, и объем книги заказов значительно изменился вместе с волатильностью рынка. Спед, в частности, указывал на степень колебаний рынка, что является разницей между лучшими ценами спроса и предложения. В статистике рынка YGG в тот день, спред был больше одного тика в 20% случаев. В эту эру различных торговых ботов, конкурирующих в книге заказов, такие ситуации становятся все более редкими.
В [1]:
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
В [2]:
books = pd.read_csv('YGGUSDT-bookTicker-2023-08-07.csv')
В [3]:
tick_size = 0.0001
В [4]:
books['date'] = pd.to_datetime(books['transaction_time'], unit='ms')
books.index = books['date']
В [5]:
books['spread'] = round(books['best_ask_price'] - books['best_bid_price'],4)
В [6]:
books['best_bid_price'][::10].plot(figsize=(10,5),grid=True);
Выход[6]:
В [7]:
books['best_bid_qty'][::10].rolling(10000).mean().plot(figsize=(10,5),grid=True);
books['best_ask_qty'][::10].rolling(10000).mean().plot(figsize=(10,5),grid=True);
Выход[7]:
В [8]:
(books['spread'][::10]/tick_size).rolling(10000).mean().plot(figsize=(10,5),grid=True);
Вне[8]:
В [9]:
books['spread'].value_counts()[books['spread'].value_counts()>500]/books['spread'].value_counts().sum()
Выход[9]:
Неравновесные котировки наблюдаются из значительной разницы в объеме ордеров между ордерами на покупку и продажу в большинстве случаев. Эта разница оказывает сильное предсказательное влияние на краткосрочные рыночные тенденции, аналогично причине, упомянутой ранее, что снижение объема ордеров на покупку часто приводит к снижению. Если одна сторона книги ордеров значительно меньше другой, при условии, что активные заказы на покупку и продажу схожи по объему, существует большая вероятность того, что меньшая сторона будет потреблена, тем самым приводя к изменениям цен. Неравновесные котировки представлены буквой
где Q_b представляет собой сумму ожидаемых ордеров на покупку (best_bid_qty) и Q_a представляет собой сумму ожидаемых ордеров на продажу (best_ask_qty).
Определите среднюю цену:
Нижеприведенный график показывает взаимосвязь между скоростью изменения средней цены в течение следующего интервала 1 и дисбалансом I. Как и ожидалось, чем больше вероятность того, что цена увеличится по мере увеличения I и чем ближе она приближается к 1, тем больше ускоряется изменение цены. В высокочастотной торговле введение промежуточной цены позволяет лучше предсказать будущие изменения цен, то есть, чем меньше будущая разница цен, тем лучше определяется промежуточная цена. Очевидно, дисбаланс ожидаемых заказов предоставляет дополнительную информацию для прогнозирования стратегии, с учетом этого, определяя взвешенную среднюю цену:
В [10]:
books['I'] = books['best_bid_qty'] / (books['best_bid_qty'] + books['best_ask_qty'])
В [11]:
books['mid_price'] = (books['best_ask_price'] + books['best_bid_price'])/2
В [12]:
bins = np.linspace(0, 1, 51)
books['I_bins'] = pd.cut(books['I'], bins, labels=bins[1:])
books['price_change'] = (books['mid_price'].pct_change()/tick_size).shift(-1)
avg_change = books.groupby('I_bins')['price_change'].mean()
plt.figure(figsize=(8,5))
plt.plot(avg_change)
plt.xlabel('I Value Range')
plt.ylabel('Average Mid Price Change Rate');
plt.grid(True)
Выход[12]:
В [13]:
books['weighted_mid_price'] = books['mid_price'] + books['spread']*books['I']/2
bins = np.linspace(-1, 1, 51)
books['I_bins'] = pd.cut(books['I'], bins, labels=bins[1:])
books['weighted_price_change'] = (books['weighted_mid_price'].pct_change()/tick_size).shift(-1)
avg_change = books.groupby('I_bins')['weighted_price_change'].mean()
plt.figure(figsize=(8,5))
plt.plot(avg_change)
plt.xlabel('I Value Range')
plt.ylabel('Weighted Average Mid Price Change Rate');
plt.grid(True)
Выход[13]:
Из графика можно наблюдать, что взвешенная средняя цена показывает меньшие колебания по сравнению с различными значениями I, что указывает на то, что она лучше подходит. Тем не менее, все еще есть некоторые отклонения, особенно около 0,2 и 0,8. Это говорит о том, что я все еще предоставляю дополнительную информацию. Предположение о полностью линейной связи между термином коррекции цены и I, как подразумевается взвешенной средней ценой, не соответствует действительности. Из графика можно увидеть, что скорость отклонения увеличивается, когда я приближаюсь к 0 и 1, что указывает на нелинейную связь.
Чтобы дать более интуитивное представление, вот переопределение I:
Пересмотренное определение I:
На данный момент:
При наблюдении можно заметить, что взвешенная средняя цена является коррекцией к средней средней цене, где срок коррекции умножается на спред. Термин коррекции является функцией I, а взвешенная средняя цена предполагает простое отношение I/2. В этом случае преимущество скорректированного распределения I (-1, 1) становится очевидным, поскольку I симметричен вокруг происхождения, что делает удобным поиск подходящей связи для функции. Исследуя график, кажется, что эта функция должна удовлетворять силы I, поскольку она выстраивается с быстрым ростом по обеим сторонам и симметричность происхождения. Кроме того, можно наблюдать, что значения, близкие к происхождению, близки к линейным. Кроме того, когда I 0, результат функции 0, а когда I результат 1,5.
Здесь N является положительным четным числом, после фактического тестирования лучше, когда N составляет 8. До сих пор в этой статье представлена модифицированная взвешенная средняя цена:
На данный момент прогноз изменений средней цены больше не имеет существенной связи с I. Хотя этот результат немного лучше, чем простая взвешенная средняя цена, он все еще не применим в реальных торговых сценариях. Это всего лишь предложенный подход.МикроценыИсследователи могут исследовать этот подход дальше.
В [14]:
books['I'] = (books['best_bid_qty'] - books['best_ask_qty']) / (books['best_bid_qty'] + books['best_ask_qty'])
В [15]:
books['weighted_mid_price'] = books['mid_price'] + books['spread']*books['I']/2
bins = np.linspace(-1, 1, 51)
books['I_bins'] = pd.cut(books['I'], bins, labels=bins[1:])
books['weighted_price_change'] = (books['weighted_mid_price'].pct_change()/tick_size).shift(-1)
avg_change = books.groupby('I_bins')['weighted_price_change'].mean()
plt.figure(figsize=(8,5))
plt.plot(avg_change)
plt.xlabel('I Value Range')
plt.ylabel('Weighted Average Mid Price Change Rate');
plt.grid(True)
Выход[15]:
В [16]:
books['adjust_mid_price'] = books['mid_price'] + books['spread']*books['I']*(books['I']**8+1)/4
bins = np.linspace(-1, 1, 51)
books['I_bins'] = pd.cut(books['I'], bins, labels=bins[1:])
books['adjust_mid_price'] = (books['adjust_mid_price'].pct_change()/tick_size).shift(-1)
avg_change = books.groupby('I_bins')['adjust_mid_price'].mean()
plt.figure(figsize=(8,5))
plt.plot(avg_change)
plt.xlabel('I Value Range')
plt.ylabel('Weighted Average Mid Price Change Rate');
plt.grid(True)
Выход[16]:
Средняя цена имеет решающее значение для высокочастотных стратегий, поскольку служит прогнозом краткосрочных будущих цен. Поэтому важно, чтобы средняя цена была максимально точной. Ранее обсужденные подходы к средней цене основаны на данных книги заказов, поскольку в анализе используется только верхний уровень книги заказов. В режиме реального времени стратегии должны использовать все доступные данные, включая торговые данные, для проверки предсказаний средней цены по отношению к фактическим ценам на транзакции.