Synthetischer Hawkes-Vergleich für 114 gleichzeitige Ereignisse: Pre-Batch 183.475922 nats, zeilenweise Aktualisierung 396.770155 nats, Differenz 213.294233 nats; Kompensator je 48.237046 nats.
Abbildung: zwei Bewertungsregeln im synthetischen Batch, keine AAPL-Modellanpassung.

Beim Aufbereiten eines NASDAQ-ITCH-Orderstroms stieß ich auf eine Zahl, die ich nicht einfach an eine gewöhnliche Hawkes-Schleife mit Zustandsaktualisierung nach jeder Zeile übergeben wollte: 114.

In den AAPL-Daten der regulären Handelssitzung vom 30. Juli 2019 haben 114 execution-Nachrichten denselben Nanosekunden-Zeitstempel. Batches mit 131 und 187 Zeilen kommen jeweils ebenfalls einmal vor. Von 49,172 Ausführungsnachrichten teilen sich 30,080 (61.17%) ihren Zeitstempel mit mindestens einer weiteren Zeile. Gleichstände sind alltäglich; Hunderter-Batches liegen im extremen Rand der Verteilung.

„Ausführungsereignis“ bezeichnet hier eine ITCH-Nachrichtenzeile gemäß unserer Forschungsdefinition, nicht 114 verschiedene Aufträge oder den Nachweis, dass 114 Abschlüsse physikalisch gleichzeitig stattfanden.

Das Problem: Aktualisiert ein Algorithmus die Hawkes-Anregung nach jeder Eingabezeile, wird selbst bei Zeitdifferenz null die 114. Zeile von den 113 vorherigen angeregt. Bei einer asymmetrischen Anregungsmatrix zwischen Ereignistypen kann sich der Score allein durch Umordnen der Dateizeilen ändern. Welche zeitliche Reihenfolge darf das Modell innerhalb desselben aufgezeichneten Zeitstempels unterstellen?

Unsere Entscheidung fiel vor dem Fit: nach Symbol und ganzzahligem Nanosekunden-Zeitstempel gruppieren, sämtliche Ereignisse mit der Historie vor dem Batch bewerten und den Zustand erst danach um die tatsächlichen Häufigkeiten aktualisieren. Die Übertragungsreihenfolge der Börsennachrichten ist Information, aber ohne zusätzliches Beobachtungsmodell keine gemessene physikalische Zeit unterhalb einer Nanosekunde.

Gleiche Zeitstempel sind häufig – 114 Zeilen sind ein Extremfall

Die offizielle Nasdaq-TotalView-ITCH-5.0-Spezifikation definiert Zeitstempel als Nanosekunden seit Mitternacht. E bedeutet Order Executed, C Order Executed With Price. Auch ein und dieselbe Auftragsreferenz kann in mehreren Teilausführungsnachrichten erscheinen.

Für die Studie definieren wir drei Ereignistypen: add=A/F, cancel_delete=X/D und execution=E/C. Bei C zählen Printable=Y und Printable=N; es handelt sich nicht bloß um druckbare Trades. P (Trade mit nicht angezeigter Order) und Q (Cross Trade) bleiben draußen. Das ist eine Forschungsdefinition und keine allgemeingültige Nasdaq-Taxonomie sämtlicher Umsätze.

Die folgende intern geprüfte Aggregation gilt für AAPL am 2019-07-30, 09:30–16:00 Uhr US-Ostküstenzeit, also die gesamte reguläre Sitzung:

KennzahlBeobachteter Wert
execution-Nachrichtenzeilen49,172
Verschiedene Nanosekunden-Zeitstempel29,379
Zeitstempel mit mehreren Zeilen10,287
Zeilen mit identischem Zeitstempel30,080 (61.17%)
Median / Modus der Batchgröße bei Gleichständen2 / 2 Zeilen
Batches mit 2–3 Zeilen8,439 (82.04% der gleichzeitigen Batches)
Ein Batch mit genau 114 Zeilen1
Größere Batches mit 131 / 187 ZeilenJeweils 1

Eine frühere Analyse nutzte das gemeinsame Zeitfenster 09:30–11:00 über mehrere Tage. Diese beiden Abdeckungen dürfen nicht vermischt werden. Das gespeicherte Histogramm enthält Batchgrößen, aber nicht die individuellen Order-Identitäten oder eine rekonstruierbare physikalische Reihenfolge.

Über alle 29,379 Zeitstempel liegen im Mittel 1.67 Zeilen vor. Für die 10,287 Mehrfach-Batches sind es 2.92; Median und Modus sind jeweils 2. Ein Batch mit 114 Zeilen ist rund 39-mal so groß wie dieser Mittelwert. Nur drei Batches erreichen 114 oder mehr Zeilen (114, 131, 187). Als Stresstest eignet sich das hervorragend, als typischer Fall nicht.

Dass 61.17% der Zeilen Zeitstempel teilen, beweist nicht allein, dass Hawkes-Parameter unidentifizierbar sind. Die pre-batch-Konvention verzichtet auf unbekannte Subnanosekunden-Abstände innerhalb des Batches; Abstände und Typkombinationen zwischen Batches liefern weiterhin Information.

Wer darf zum selben Zeitpunkt wen anregen?

Für einen Hawkes-Prozess mit drei Ereignistypen und exponentiellem Kernel schreiben wir die bedingte Intensität als:

lambda_k(t-) = mu_k(t)
             + sum_j [alpha[k,j] / tau
               * sum_{u<t} m_j(u) * exp(-(t-u)/tau)]

k bezeichnet den Zieltyp, j die Quelle; m_j(u) ist die tatsächliche Zahl der Zeilen vom Typ j am Zeitstempel u. Die Matrixrichtung lautet Ziel × Quelle. mu_k hat die Einheit Ereignisse/s, tau Sekunden und alpha[k,j] ist eine dimensionslose integrierte Anregung pro Quellereignis. Der unmittelbare Kernel-Koeffizient ist daher alpha[k,j]/tau (1/s); nach zeitlicher Integration erscheint alpha.

Entscheidend ist das strikte u<t. Der aktuelle Batch darf nicht schon in seiner eigenen Historie stehen. Sein Ereignisterm lautet:

event_term(t) = sum_k m_k(t) * log(lambda_k(t-))

Zuerst werden alle lambda_k(t-) aus derselben Historie bestimmt; erst nach der Bewertung wird der Zustand einmal mit m_add, m_cancel_delete und m_execution fortgeschrieben. 114 Zeilen dürfen nicht zu einem Ereignis zusammenfallen. In synthetischen Regressionen prüfen wir die Unabhängigkeit vom Zeilenwechsel, getrennte Symbole und den Reset zwischen Sitzungen.

Die Reihenfolge der tatsächlich gesendeten Nachrichten könnte man in einem anderen Beobachtungsmodell verwenden. Ohne explizite Zuordnung zu Ereigniszeiten ist die sequentielle Bewertung aber keine harmlose Optimierung derselben Likelihood.

Ein künstlicher 114-Zeilen-Fall macht den Unterschied messbar

Das Folgende ist keine AAPL-Parameterschätzung, sondern ein ausführbares Beispiel nur mit der Python-Standardbibliothek: 114 Ereignisse desselben Typs zum Sitzungsbeginn, keine vorherige Anregung, mu=5 Ereignisse/s, alpha=0.6, tau=1 s; danach wird eine Sekunde beobachtet.

import math

m, mu, alpha, tau, horizon = 114, 5.0, 0.6, 1.0, 1.0

# Den gesamten Batch mit der Intensität vor dem Batch bewerten
pre_batch = m * math.log(mu)

# Kontrastfall: frühere Zeilen desselben Zeitstempels regen spätere an
row_ordered = math.fsum(
    math.log(mu + alpha * i / tau) for i in range(m)
)

# Vollständige Likelihood zieht das Integral im gesamten Beobachtungsfenster ab
baseline_area = mu * horizon
excitation_area = alpha * m * (-math.expm1(-horizon / tau))
compensator = baseline_area + excitation_area

print(f"prebatch_event_log_term: {pre_batch:.6f}")
print(f"row_ordered_event_log_term: {row_ordered:.6f}")
print(f"artificial_excess: {row_ordered - pre_batch:.6f}")
print(f"one_second_compensator: {compensator:.6f}")
print(f"one_second_full_LL: {pre_batch - compensator:.6f}")

Die tatsächliche Ausführung unter Python 3.13.5 in einer isolierten Linux-Umgebung endete mit Code 0:

prebatch_event_log_term: 183.475922
row_ordered_event_log_term: 396.770155
artificial_excess: 213.294233
one_second_compensator: 48.237046
one_second_full_LL: 135.238876

Nur die Annahme, dass frühere Zeilen desselben aufgezeichneten Augenblicks spätere Zeilen anregen dürfen, erhöht den Ereignis-Logterm um 213.294233 nats. Dabei enthalten beide Varianten nach dem Batch dieselben 114 Ereignisse in der Historie. Der Kompensator über die folgende Sekunde ist für diesen Batch ohne Zeitdauer identisch: 48.237046 nats. Der vollständige Score beträgt 348.533109 bei zeilenweiser Anregung und 135.238876 bei pre-batch; die Differenz bleibt 213.294233 nats.

Das ist weder ein realer Prognosegewinn noch der Vergleich zweier exakter Likelihoods für ein gemeinsames kontinuierliches Beobachtungsmodell. Auch pre-batch verliert nicht die spätere Wirkung: nach einer Sekunde tragen die 114 Ereignisse unter diesen künstlichen Parametern 114 × 0.6 × exp(-1) ≈ 25.163 Ereignisse/s zur Eigenintensität bei.

Ohne Kompensator ist der Ereignisterm keine vollständige Likelihood

Die Summe der log(lambda)-Werte an den Ereignissen reicht nicht aus. Von der Punktprozess-Likelihood muss zusätzlich die Intensität über die gesamte gültige Beobachtungssitzung integriert und abgezogen werden:

LL = sum_k sum_batches m_k(t) * log(lambda_k(t-))
     - sum_k integral_session lambda_k(t) dt

Der vorab festgelegte tageszeitliche Basisverlauf umfasst 78 Fünfminutenintervalle von 09:30 bis 16:00 Uhr (390 Minuten). Das Basisterm-Integral nutzt die exakte halb offene Überlappung mit dem Sitzungsfenster. Vergangene Batches tragen ihre wirklichen Multiplizitäten in das exponentielle Kernintegral ein.

baseline_area[k] = sum_r mu[k,r] * overlap_seconds(r, session)

excitation_area[k] = sum_j sum_{u in session}
    alpha[k,j] * m_j(u) * (1 - exp(-(end-u)/tau))

Für kurze Zeitabstände verwendet die Implementierung -expm1(-(end-u)/tau), um Auslöschung bei der Subtraktion nahezu gleicher Zahlen zu vermeiden. Im künstlichen Ein-Sekunden-Beispiel beträgt die Basisfläche 5, die integrierte Anregung etwa 43.237046 und der Kompensator somit 48.237046. Die vollständige pre-batch-LL ist 135.238876, nicht bloß der Ereignisterm 183.475922.

Was zeigt das reale Batchgrößen-Histogramm in künstlichen Szenarien?

Das 114-Zeilen-Beispiel erklärt den Mechanismus. Für eine Empfindlichkeitsrechnung verwenden wir zusätzlich das bereits gespeicherte Histogramm der AAPL-execution-Batchgrößen über die gesamte Sitzung 2019-07-30 – nur als Multiplizitäts-Eingabe für künstliche Parameter. Weder wurden rohe ITCH-Daten erneut gelesen noch echte Hawkes-Parameter geschätzt.

Wir betrachten ausschließlich positive Selbstanregung des Ausführungstyps. Wenn die Intensität lambda^- unmittelbar vor jedem Batch mindestens dem künstlich angesetzten mu>0 entspricht, erfüllt die zeilenweise Anregungsdifferenz bei Batchgröße m folgende Ungleichung:

0 <= Delta(m) = sum_{i=0}^{m-1} log(1 + alpha*i/(tau*lambda^-))
   <= sum_{i=0}^{m-1} log(1 + alpha*i/(tau*mu))

Die rechte Seite ist eine bedingte obere Schranke für dieses Ein-Typ-Szenario, keine allgemeine Fehlerschranke für die vollständige Drei-Typen-Hawkes-Likelihood. Weder die wahre Vorabintensität noch weitere gleichzeitig auftretende Typen sind bekannt.

Mit mu=5 Ereignissen/s ergeben sich aus den gespeicherten Häufigkeiten:

Angenommenes alphatau=0.1 stau=1 stau=10 s
0.18,392.651,436.32178.46
0.317,088.263,472.79500.41
0.625,186.195,837.61928.45

Alle Werte sind in nats und beruhen auf erfundenen Parameterannahmen. Für mu=5, alpha=0.3, tau=1 beträgt die kumulierte bedingte Schranke 3,472.79 nats, geteilt durch 49,172 Ausführungszeilen 0.0706 nats/Zeile. Ein typischer Batch aus zwei beziehungsweise drei Zeilen hat unter derselben Annahme 0.0583 bzw. 0.1716 nats als obere Schranke. Ändert man die künstliche Intensitätsuntergrenze mu auf 1 oder 20, wird die Summe 11,044.42 bzw. 1,125.70 nats.

Über die neun Kombinationen liegt die bedingte Schranke zwischen 178.46 und 25,186.19 nats, entsprechend 0.00363–0.51221 nats/Zeile. Daraus lassen sich keine echten AAPL-Likelihood-Fehler oder gefitteten Marktparameter ableiten.

Entfernt man im mittleren Szenario die größten Batches, erhält man:

Ausgeschlossene größte BatchesRückgang der oberen Schranke (nats)Anteil an ursprünglicher Schranke
187 Zeilen (Top 1)321.549.26%
187, 131, 114 Zeilen (Top 3)665.6219.17%
Die 10 größten Batches1,123.5732.35%

Die drei größten Batches umfassen nur 432 Zeilen, stellen aber nahezu ein Fünftel dieser speziellen angenommenen Schranke. Das gespeicherte Histogramm enthält keine Uhrzeiten dieser Extrem-Batches; Aussagen über Eröffnungs-/Schlussauktionen, Matchingmechanismen oder Zeitstempel-Encoding sind deshalb nicht möglich.

Diese künstliche Sensitivitätsrechnung und der Abgleich des Histogramms wurden in einer gesonderten 13/13-Testsuite geprüft. Die nachfolgenden 99 Forschungstests sind eine andere Ausführung.

Was haben die 99 Tests wirklich bewiesen?

Die reale AAPL-Aggregation zeigt, dass gleich gestempelte Ausführungszeilen existieren und welche Größen sie erreichen. Synthetische Tests mit bekannten Parametern prüfen dagegen die Rechenvorschrift für Batch-Score, Zustand und Kompensator. Diese Evidenztypen sind nicht austauschbar.

Synthetische TestsWas geprüft wurde
Batch-Bewertung (10)Einheitliche Intensität vor Batchbeginn, volle Multiplizität, Invarianz gegenüber der Zeilenfolge
Vollständige Likelihood (33)Basis- und Kernel-Kompensator; analytische gegen numerische Integration
M0/M1/M2-Verträge (34)Homogener Poisson, saisonaler NHPP mit 78 Intervallen und Hawkes mit drei Typen bei bekannten Parametern
Synthetische Ereignisfolgen (22)Ogata-Thinning mit festem Seed, unabhängige Summation, Determinismus zweier Prozesse
Gesamt99/99 Forschungstests bestanden (Python 3.13.5, isoliertes Linux x86_64)

Ein eigens konstruierter Testfall umfasst 209 synthetische Ereignisse in vier Zeitstempelgruppen: 90 Adds bei Sitzungsbeginn, 114 Executions nach +1 s, 3 Cancel/Delete nach +2 s, nach +3 s noch 1 Add und 1 Execution zusammen. Die Batchgrößen lauten 90/114/3/2. Gegen einen unabhängig implementierten direkten Historien-Summen-/Integrationspfad betrug die größte absolute Abweichung etwa 1.42e-14; eine Umkehr der Eingabezeilen änderte den Score nicht.

Zwei weitere durch Ogata-Thinning erzeugte kontinuierliche synthetische Ereignisströme enthielten 285 beziehungsweise 265 Ereignisse. Die unabhängigen Likelihood-Vergleiche wichen höchstens um etwa 7.11e-15 ab. Die simulierten Ströme erzeugten nicht von selbst 114 exakte Zeitstempel-Gleichstände: der Extrem-Batch ist absichtlich konstruiert.

Die 99 Tests wurden historisch unter Python 3.13.5 / isoliertem Linux x86_64 ausgeführt. Das ist kein GitHub-Actions-PASS des gegenwärtigen Redaktions-HEAD. Weder reale Marktparameter-Fits noch Hold-out-Scores oder eine Überlegenheit gegenüber saisonalem NHPP wurden bisher nachgewiesen.

Die Grenze: Arbeits-Likelihood statt exakter Beobachtungsdichte

Bei einem einfachen kontinuierlichen Punktprozess haben exakt gleichzeitige Ankünfte normalerweise Wahrscheinlichkeit null. ITCH-Zeitstempel sind beobachtete bzw. kodierte Nanosekundenmarkierungen; die bekannte Nachrichtenreihenfolge enthüllt keine darunterliegende physikalische Zeit. Unsere pre-batch-Arbeits-Likelihood (auch Pseudo-Likelihood-Score) ist somit eine offen benannte Konvention, keine abgeleitete exakte gemeinsame Dichte für zeitlich quantisierte Beobachtungen. Ohne definierte Teildichten und Abhängigkeitsbehandlung ist auch die Bezeichnung composite likelihood nicht gerechtfertigt.

Für Zählungen in festen Zeitintervallen kommt ein diskretes Count-Modell infrage; für nicht beobachtete Ankünfte innerhalb der Intervalle ein Modell mit Intervallzensierung. Das Durchspielen alternativer Reihenfolgen kleiner Batches ist eine Sensitivitätsanalyse, kein universeller Codeersatz.

Wenn bei identischen Daten, Gruppen und Beobachtungsmodellen beide verglichenen Scores dieselbe parameterunabhängige Konstante C(D) auslassen, hebt sie sich in der Differenz auf: (LL_A+C(D))-(LL_B+C(D))=LL_A-LL_B. Ein -sum log(m!) kann in bestimmten diskreten Zählmodellen so eine Konstante sein. Dadurch bleibt die absolute LL nicht unverändert, und allein das Hinzufügen des Fakultätsterms macht pre-batch nicht zu einer exakten Beobachtungs-Likelihood. Andere Gruppierungen oder Zeitkonventionen verletzen möglicherweise die Voraussetzung.

Ebenso darf ein klassischer Chi-Quadrat-Likelihood-Ratio-Test nicht automatisch angewandt werden: Nichtnegative Anregungsparameter liegen am Rand; Abklingparameter können unter der Nullhypothese unidentifizierbar sein.

Residuen bei gleichzeitigen Zeitstempeln prüfen

Wer 114 gleich gestempelte Zeilen als 114 aufeinanderfolgende Ankünfte behandelt, erzeugt sehr viele Null-Abstände und verzerrt die Zeitreskalierung. Unser vorab definierter Diagnoseplan bildet Residuen auf Basis der eindeutigen Zeitstempel je Ereignistyp und führt die Batch-Multiplizität separat. QQ-Plots, Autokorrelation und KS-Abstände beschreiben die Abweichung; ein klassischer KS-p-Wert unter der Annahme kontinuierlicher Ankünfte ohne Ties gilt nicht als formaler Test. Für späteres Bootstrap oder Permutationen braucht es zunächst Nullhypothese, Datengenerator und eine Resampling-Einheit, die Batch-Abhängigkeiten erhält.

Die Reihenfolge der Zeilen in einer Datei darf nicht heimlich zur kausalen Ereigniszeit werden.

Oeffentliche Reproduktionsdateien: Python-Skripte, Histogramm, Tests und SHA-256-Pruefsummen.