В предыдущей статье я представил, как моделировать совокупный объем торговли и проанализировал феномен влияния цены. В этой статье я продолжу анализировать данные о заказах на сделки. YGG недавно запустил контракты на основе Binance U, и колебания цен были значительными, причем объем торговли даже превысил BTC в один момент. Сегодня я проанализирую его.
Как правило, предполагается, что время прибытия заказов следует процессу Поасона.Процесс рыболовстваЗдесь я предоставлю эмпирические доказательства.
Я загрузил данные AggTrades за 5 августа, которые состоят из 1 931 193 сделок, что довольно значительно. Во-первых, давайте посмотрим на распределение ордеров на покупку. Мы можем увидеть негладкий местный пик около 100 мс и 500 мс, который, вероятно, вызван айсбергными ордерами, размещенными торговыми ботами с регулярными интервалами. Это также может быть одной из причин необычных рыночных условий в тот день.
Функция массы вероятности (PMF) распределения Поасона дается следующей формулой:
Где:
В процессе Поасона временные интервалы между событиями следуют экспоненциальному распределению.
Процесс Поасона недооценивает частоту длительных временных интервалов и переоценивает частоту коротких временных интервалов. (Фактивное распределение интервалов ближе к модифицированному распределению Парето)
В [1]:
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
В [2]:
trades = pd.read_csv('YGGUSDT-aggTrades-2023-08-05.csv')
trades['date'] = pd.to_datetime(trades['transact_time'], unit='ms')
trades.index = trades['date']
buy_trades = trades[trades['is_buyer_maker']==False].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'
})
buy_trades['interval']=buy_trades['transact_time'] - buy_trades['transact_time'].shift()
buy_trades.index = buy_trades['date']
В [10]:
buy_trades['interval'][buy_trades['interval']<1000].plot.hist(bins=200,figsize=(10, 5));
Выход[10]:
В [20]:
Intervals = np.array(range(0, 1000, 5))
mean_intervals = buy_trades['interval'].mean()
buy_rates = 1000/mean_intervals
probabilities = np.array([np.mean(buy_trades['interval'] > interval) for interval in Intervals])
probabilities_s = np.array([np.e**(-buy_rates*interval/1000) for interval in Intervals])
plt.figure(figsize=(10, 5))
plt.plot(Intervals, probabilities)
plt.plot(Intervals, probabilities_s)
plt.xlabel('Intervals')
plt.ylabel('Probability')
plt.grid(True)
Выход[20]:
При сравнении распределения количества случаев порядка в течение 1 секунды с распределением Поасона, разница также значительна.
Другими словами, в реальной среде частота возникновения заказов является непостоянной, и она должна обновляться в режиме реального времени.
В [190]:
result_df = buy_trades.resample('1S').agg({
'price': 'count',
'quantity': 'sum'
}).rename(columns={'price': 'order_count', 'quantity': 'quantity_sum'})
В [219]:
count_df = result_df['order_count'].value_counts().sort_index()[result_df['order_count'].value_counts()>20]
(count_df/count_df.sum()).plot(figsize=(10,5),grid=True,label='sample pmf');
from scipy.stats import poisson
prob_values = poisson.pmf(count_df.index, 1000/mean_intervals)
plt.plot(count_df.index, prob_values,label='poisson pmf');
plt.legend() ;
Выход[219]:
Из анализа интервалов ордеров ранее можно сделать вывод, что фиксированные параметры не подходят для реальных рыночных условий, и ключевые параметры, описывающие рынок в стратегии, должны обновляться в режиме реального времени. Наиболее простое решение - использовать скользящую среднюю. Два графика ниже показывают частоту заказов на покупку в течение 1 секунды и средний объем торговли с размером окна 1000. Можно заметить, что в торговле наблюдается явление кластеризации, когда частота заказов значительно выше, чем обычно в течение определенного периода времени, а объем также увеличивается синхронно. Здесь среднее значение предыдущих значений используется для прогнозирования последнего абсолютного значения, а средняя погрешность остатков используется для измерения качества прогноза.
Из графиков мы также можем понять, почему частота порядка так сильно отклоняется от распределения Поасона.
Оказалось, что использование среднего значения предыдущих двух секунд для прогнозирования дает наименьшую остаточную ошибку, и это намного лучше, чем просто использование среднего значения для результатов прогнозирования.
В [221]:
result_df['order_count'].rolling(1000).mean().plot(figsize=(10,5),grid=True);
Выход[221]:
В [193]:
result_df['quantity_sum'].rolling(1000).mean().plot(figsize=(10,5),grid=True);
Выход[193]:
В [195]:
(result_df['order_count'] - result_df['mean_count'].mean()).abs().mean()
Выход[195]:
6.985628185332997
В [205]:
result_df['mean_count'] = result_df['order_count'].rolling(2).mean()
(result_df['order_count'] - result_df['mean_count'].shift()).abs().mean()
Выход[205]:
3.091737586730269
Эта статья кратко объясняет причины отклонения интервалов времени заказа от процесса Поасона, в основном из-за изменения параметров с течением времени. Для точного прогнозирования рынка стратегии должны делать прогнозы фундаментальных параметров рынка в режиме реального времени. Остатки могут быть использованы для измерения качества прогнозов. Пример, приведенный выше, является простой демонстрацией, и есть обширные исследования по конкретному анализу временных рядов, кластеризации волатильности и другим связанным темам, вышеуказанную демонстрацию можно еще больше улучшить.