Überlegungen zu Hochfrequenz-Handelsstrategien (4)

Schriftsteller:Lydia., Erstellt: 2023-08-10 13:44:30, Aktualisiert: 2023-09-12 15:51:24

img

Überlegungen zu Hochfrequenz-Handelsstrategien (4)

In dem vorangegangenen Artikel wurde gezeigt, wie wichtig die dynamische Anpassung von Parametern ist und wie man die Qualität von Schätzungen durch die Untersuchung der Auftragszugabeintervalle bewerten kann.

Tiefendaten

Binance bietet historische Daten-Downloads für best_bid_price (der höchste Kaufpreis), best_bid_quantity (die Menge zum besten Gebotspreis), best_ask_price (der niedrigste Verkaufspreis), best_ask_quantity (die Menge zum besten Gebotspreis) und transaction_time. Diese Daten umfassen nicht die zweite oder tiefere Auftragsbuch-Level. Die Analyse in diesem Artikel basiert auf dem YGG-Markt am 7. August, der mit über 9 Millionen Datenpunkten erhebliche Volatilität erlebte.

Zuerst werfen wir einen Blick auf die Marktbedingungen an diesem Tag. Es gab große Schwankungen, und das Auftragsbuchvolumen änderte sich signifikant zusammen mit der Marktvolatilität. Der Spread zeigte insbesondere das Ausmaß der Marktschwankungen an, das ist der Unterschied zwischen den besten Ask- und Bid-Preisen. In den Statistiken des YGG-Marktes an diesem Tag war der Spread 20% der Zeit größer als ein Ticker. In dieser Ära verschiedener im Auftragsbuch konkurrierender Trading-Bots werden solche Situationen zunehmend seltener.

In [1]:

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

In [2]:

books = pd.read_csv('YGGUSDT-bookTicker-2023-08-07.csv')

In [3]:

tick_size = 0.0001

In [4]:

books['date'] = pd.to_datetime(books['transaction_time'], unit='ms')
books.index = books['date']

In [5]:

books['spread'] = round(books['best_ask_price'] - books['best_bid_price'],4)

In [6]:

books['best_bid_price'][::10].plot(figsize=(10,5),grid=True);

Ausgeschaltet[6]:

img

In [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);

Aus[7]:

img

In [8]:

(books['spread'][::10]/tick_size).rolling(10000).mean().plot(figsize=(10,5),grid=True);

Außen[8]:

img

In [9]:

books['spread'].value_counts()[books['spread'].value_counts()>500]/books['spread'].value_counts().sum()

Ausgeschaltet[9]:

img

Ungleichgewichte Zitate

Ungleichgewichte Quoten werden durch den signifikanten Unterschied in den Auftragsvolumina zwischen den Kauf- und Verkaufsbestellungen in den meisten Fällen beobachtet. Dieser Unterschied hat eine starke vorausschauende Wirkung auf kurzfristige Markttrends, ähnlich dem früher erwähnten Grund, dass eine Abnahme des Kaufbestellungsvolumens oft zu einem Rückgang führt. Wenn eine Seite des Auftragsbuchs signifikant kleiner ist als die andere, unter der Annahme, dass die aktiven Kauf- und Verkaufsbestellungen ähnlich sind, besteht eine größere Wahrscheinlichkeit, dass die kleinere Seite verbraucht wird, wodurch Preisänderungen vorgenommen werden. Ungleichgewichte Quoten werden durch den Buchstaben I dargestellt.

img

Hierbei stellt Q_b den Betrag der ausstehenden Kaufbestellungen dar (best_bid_qty) und Q_a den Betrag der ausstehenden Verkaufsbestellungen (best_ask_qty).

Definition des mittleren Preises:

img

Die folgende Grafik zeigt die Beziehung zwischen der Veränderungsrate des mittleren Preises über das nächste 1-Intervall und dem Ungleichgewicht I. Je wahrscheinlicher der Preis steigt, je mehr ich steige und je näher er an 1 kommt, desto schneller beschleunigt sich die Preisänderung. Im Hochfrequenzhandel soll der Zwischenpreis eingeführt werden, um zukünftige Preisänderungen besser vorherzusagen, dh je kleiner die zukünftige Preisdifferenz ist, desto besser wird der Zwischenpreis definiert. Offensichtlich liefert das Ungleichgewicht der ausstehenden Aufträge zusätzliche Informationen für die Vorhersage der Strategie, wobei der gewichtete mittlere Preis definiert wird:

img

In [10]:

books['I'] = books['best_bid_qty'] / (books['best_bid_qty'] + books['best_ask_qty'])

In [11]:

books['mid_price'] = (books['best_ask_price'] + books['best_bid_price'])/2

In [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)

Ausgeschaltet:

img

In [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)

Aus dem Spiel[13]:

img

Anpassung des gewichteten mittleren Preises:

Aus der Grafik kann beobachtet werden, dass der gewichtete Mittelpreis im Vergleich zu verschiedenen Werten von I kleinere Schwankungen zeigt, was darauf hindeutet, dass er besser passt. Es gibt jedoch noch einige Abweichungen, insbesondere um 0,2 und 0,8. Dies deutet darauf hin, dass ich immer noch zusätzliche Informationen bereitstelle. Die Annahme einer vollständig linearen Beziehung zwischen dem Preiskorrekturbegriff und I, wie durch den gewichteten Mittelpreis impliziert, entspricht nicht der Realität. Aus der Grafik kann gesehen werden, dass die Abweichungsgeschwindigkeit steigt, wenn ich mich 0 und 1 nähere, was auf eine nichtlineare Beziehung hinweist.

Um eine intuitivere Darstellung zu liefern, gibt es hier eine Neudefinition von I:

Überarbeitete Definition von I:

img

Zu diesem Zeitpunkt:

img

Bei Beobachtung kann festgestellt werden, dass der gewichtete Mittelpreis eine Korrektur zum mittleren Durchschnittspreis ist, wobei der Korrekturzeitraum durch den Spread multipliziert wird. Der Korrekturzeitraum ist eine Funktion von I, und der gewichtete Mittelpreis geht von einer einfachen Beziehung von I/2 aus. In diesem Fall wird der Vorteil der angepassten I-Verteilung (-1, 1) offensichtlich, da I um den Ursprung symmetrisch ist, was es bequem macht, eine passende Beziehung für die Funktion zu finden. Durch die Untersuchung des Graphs scheint es, dass diese Funktion die Potenzen von I erfüllen sollte, da sie mit dem schnellen Wachstum auf beiden Seiten und der Symmetrie des Ursprungs übereinstimmt. Außerdem kann beobachtet werden, dass Werte in der Nähe des Ursprungs nahe an linear sind. Darüber hinaus, wenn I 0, ist das Ergebnis der Funktion 0, und wenn I 1, das Ergebnis ist 0.5. Daher wird spekuliert, dass die Funktion die Formel:

img

Hier ist N eine positive paarzahl, nach tatsächlichen Tests ist es besser, wenn N 8 ist. Bisher präsentiert dieses Papier den modifizierten gewichteten mittleren Preis:

img

An diesem Punkt ist die Vorhersage von mittleren Preisänderungen nicht mehr signifikant mit I verbunden. Obwohl dieses Ergebnis etwas besser ist als der einfache gewichtete mittlere Preis, ist es immer noch nicht in realen Handelsszenarien anwendbar. Dies ist nur ein vorgeschlagener Ansatz.KleinstpreisDie Ergebnisse der Studie werden im Rahmen eines Markov-Kette-Ansatzes vorgestellt, und der zugehörige Code wird bereitgestellt.

In [14]:

books['I'] = (books['best_bid_qty'] - books['best_ask_qty']) / (books['best_bid_qty'] + books['best_ask_qty'])

In [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)

Ausgeschaltet[1]:

img

In [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)

Ausgeschaltet [1]:

img

Zusammenfassung

Der mittlere Preis ist für Hochfrequenzstrategien entscheidend, da er als Vorhersage von kurzfristigen zukünftigen Preisen dient. Daher ist es wichtig, dass der mittlere Preis so genau wie möglich ist. Die zuvor diskutierten Mittelkursansätze basieren auf Orderbuchdaten, da nur die oberste Ebene des Orderbuchs in der Analyse verwendet wird. Im Live-Handel sollten Strategien darauf abzielen, alle verfügbaren Daten, einschließlich Handelsdaten, zu nutzen, um Mittelkursvorhersagen gegen die tatsächlichen Transaktionspreise zu validieren. Ich erinnere mich, dass Stoikov in einem Twitter erwähnt hat, dass der reale Mittelkurs ein gewichteter Durchschnitt der Wahrscheinlichkeiten der Ausführung der Gebots- und Nachfragepreise sein sollte. Dieses Thema wurde in den vorherigen Artikeln untersucht. Aufgrund von Längenbeschränkungen werden weitere Details zu diesen Themen im nächsten Artikel diskutiert.


Mehr