Toda-Yamamoto vs Differenced Granger: Does the BTC Lead-Lag Survive?
Fast jedes veröffentlichte Granger-Kausalitätsergebnis zu Krypto wird anhand von Log-Returns berechnet. Diese Wahl ist nicht frei. Die Differenzierung macht die Reihe stationär, was der Standard-F-Test erfordert, verwirft aber auch die Ebenenbeziehung – und wenn zwei Münzen kointegriert werden, wird der differenzierte VAR falsch angegeben und der Test beantwortet eine etwas andere Frage als die, die Sie gestellt haben.
Toda und Yamamoto (1995) bieten einen Ausweg: Passen Sie den VAR an Levels mit zusätzlichen Verzögerungen an, testen Sie nur die Originale und erhalten Sie eine gültige Version unabhängig von Einheitswurzeln oder Kointegration. Es ist in der Ökonometrie gut bekannt und wird fast nie auf Krypto-Lead-Lag angewendet.
In diesem Artikel geht es also um eines: Führen Sie beide Tests für dieselben Paare über dasselbe Fenster durch und melden Sie, ob sie nicht übereinstimmen. Wenden Sie dann die ehrliche Folgemaßnahme an – eine Korrektur mehrerer korrelierter Familientests auf die resultierende Matrix und einen rollierenden p-Wert, um zu sehen, ob die „signifikante“ Verzögerung stabil genug für den Handel ist oder nur über den Schwellenwert flackert.
Die folgende Theorie ist nur so umfassend, wie nötig ist, um den Vergleich lesbar zu machen. Der Blog behandelt bereits Einheitenwurzeln, Kointegration, Datenladen, Dimensionierung und Kosten; Das sind Links, keine Abschnitte.
Was Grangers Kausalität tatsächlich behauptet

Die Granger-Kausalität ist prädiktiver Vorrang, kein Mechanismus: Granger-Ursachen wenn vorbei reduziert die Prognosefehlervarianz von jenseits der Vergangenheit schon erklärt.
Granger-Ursachen Wenn
Zwei Serien, die von einem gemeinsamen verborgenen Faktor angetrieben werden, können eine Granger-Kausalität aufweisen, ohne dass eine direkte Verbindung zwischen ihnen besteht. Im Kryptobereich ist dieser Vorbehalt nicht akademisch – BTC ist ein einziger dominanter Faktor im gesamten Altcoin-Komplex, daher ist fast jede Alt-zu-Alt-„Kausalität“ ein mögliches Artefakt mit unterschiedlichen Reaktionsgeschwindigkeiten auf denselben BTC-Schock.
Das VAR-Framework
Der Test basiert auf einer Vektorautoregression. Für zwei Variablen mit Verzögerungen:
In Matrixform ein VAR(p) mit Variablen:
Testen, ob Granger-Ursachen testet die Gelenkrestriktion in der ersten Gleichung. Die Standardroute ist ein F-Test für eingeschränkte und uneingeschränkte Restquadratsummen.
mit der asymptotisch äquivalenten Waldform . Alles, was folgt, ist eine Frage darüber, auf welche Koeffizienten diese Einschränkung angewendet wird und auf welche Daten die VAR angepasst wurde.
Lag-Auswahl
ist wichtiger, als die meisten Artikel zugeben: Zu wenige Verzögerungen verfehlen die Dynamik, zu viele verbrennen Freiheitsgrade und zerstören die Leistung.
Angemessene Suchbereiche: 1–60 für Sekundendaten, 1–30 für Minutendaten, 1–48 für Stundendaten. BIC ist hier die richtige Standardeinstellung – es ist das sparsamere Kriterium, und Lead-Lag bei flüssigen Kryptopaaren ist ein Phänomen des kurzen Gedächtnisses. Bei jedem Ergebnis unten wird der ausgewählte BIC angegeben pro Paar, anstatt eine Verzögerung im gesamten Universum zu beheben, da eine feste Verzögerung stillschweigend eine Verzögerungsauswahlauswahl in einen Signifikanzanspruch umwandelt.
Warum der Differenztest die falsche Standardeinstellung ist

Krypto-Preisreihen sind I(1). Die übliche Lösung – logarithmische Renditen nehmen – erkauft Stationarität auf Kosten des kointegrierenden Niveaus, und wenn das Paar ein langfristiges Gleichgewicht teilt, ist der differenzierte VAR falsch spezifiziert. Die Einheitswurzel- und Kointegrationsmaschinerie hinter diesem Satz (ADF, Engle-Granger mit seinen Monte-Carlo-kritischen Werten, Johansen auf einem VAR-System) wird bereits in statistische Arbitrage und Paarhandel behandelt; vermute es hier. Der Punkt ist nur, dass das übliche Mittel – Differenz, dann Test – eine modellhafte Entscheidung mit Konsequenzen ist und Toda-Yamamoto der Weg ist, diese Entscheidung zu vermeiden.
Das Toda-Yamamoto-Verfahren
Montieren Sie einen VAR mit Verzögerungen, wo ist die optimale Verzögerungsreihenfolge und ist die maximale Integrationsreihenfolge der Reihe, dann gelten Testbeschränkungen nur für die erste Verzögerungen. Das Extra Verzögerungen absorbieren die Instationarität; die Wald-Statistik zum ersten Mal Koeffizienten folgen einem Standard unabhängig davon, ob die Reihen I(0), I(1) oder kointegriert sind.
- Bestimmen – ADF und KPSS für jede Serie. Für Kryptopreise fast immer.
- Auswählen – Passen Sie einen VAR auf Ebenen an, wählen Sie ihn nach BIC aus.
- Schätzen Sie den erweiterten VAR() auf Ebenen, keine Differenzierung.
- Wald-Test zuerst verzögert sich nur, ignoriert das Extras. Ergebnis ist .
Der Vorteil: kein Kointegrations-Vortest, keine Differenzierung und korrekte Testgröße – die Ablehnungsrate unter der Null bleibt nahezu nominal, unabhängig von den Integrationseigenschaften. Der Preis besteht darin, dass Schritt 4 nicht das Richtige ist test_causality Dies ist standardmäßig der Fall, und hier gehen die meisten Implementierungen stillschweigend schief.
Implementierung

Angenommen, Sie haben bereits Minutenbalken in einem DataFrame ausgerichtet – das ccxt-Fetch-and-Index-Boilerplate befindet sich in Regimeerkennung mit HMM und der ADF-Wrapper, den Sie für Schritt 1 verwenden würden, befindet sich in statistische Arbitrage und Paarhandel.
Ein Versionshinweis, bevor dies ausgeführt wird: grangercausalitytests(..., verbose=False) war veraltet und wurde dann in Statsmodels 0.15 entfernt. Lassen Sie das Argument fallen (die Funktion druckt standardmäßig nicht mehr) oder heften Sie es an statsmodels<0.15. Der folgende Code geht von der modernen Signatur aus.
Toda-Yamamoto, richtig gemacht
Die Einschränkung muss von Hand erstellt werden. VARResults.test_causality testet alle Verzögerungen der verursachenden Variablen im angepassten Modell – auf einem erweiterten VAR(), einschließlich der Verzögerung bei der Beschränkung, was genau das ist, was Toda-Yamamoto nicht tun soll. Der Fix ist explizit Matrix gegen die vollständige Kovarianzkovarianz:
import numpy as np
from scipy.stats import chi2
from statsmodels.tsa.api import VAR
def toda_yamamoto_test(data, target, predictor, max_lag=15, d_max=1,
significance=0.05):
"""
Toda-Yamamoto Granger causality on levels (no differencing).
Fits VAR(p + d_max) and applies a Wald test to the predictor's
coefficients at lags 1..p ONLY, leaving the d_max augmenting lags
unrestricted. Statistic is chi2(p).
"""
pair = data[[target, predictor]].dropna()
n_vars = pair.shape[1]
target_idx = list(pair.columns).index(target)
pred_idx = list(pair.columns).index(predictor)
model = VAR(pair)
p = model.select_order(maxlags=max_lag).bic or 1
res = model.fit(p + d_max)
beta = res.params.values.ravel(order="F")
cov = res.cov_params()
cov = cov.values if hasattr(cov, "values") else np.asarray(cov)
n_per_eq = res.params.shape[0]
idx = [target_idx * n_per_eq + 1 + lag * n_vars + pred_idx
for lag in range(p)] # first p lags only
R = np.zeros((p, beta.size))
R[np.arange(p), idx] = 1.0
Rb = R @ beta
V = R @ cov @ R.T
wald = float(Rb @ np.linalg.solve(V, Rb)) # no pinv: V must be PD
p_value = float(chi2.sf(wald, df=p))
return {
"target": target, "predictor": predictor,
"p": p, "augmented_lag": p + d_max, "d_max": d_max,
"wald_stat": wald, "p_value": p_value,
"significant": p_value < significance,
}
Zwei Details, die leicht falsch gemacht werden können und die den Test ungültig machen, wenn Sie dies tun. Erstens muss die Indexarithmetik mit der Abflachung von statsmodels übereinstimmen params — Überprüfen Sie dies an einem angepassten Modell beta[target_idx * n_per_eq + 1] gleicht res.params.iloc[1, target_idx] bevor Sie einem p-Wert vertrauen. Zweitens, verwenden np.linalg.solve, nicht pinv: Wenn Ist singulär, ist die Einschränkung degeneriert und der Lauf sollte lautstark fehlschlagen, anstatt eine plausibel aussehende Zahl zurückzugeben. Eine Pseudoumkehrung hier ist, wie fehlerhafte Wald-Tests die Codeüberprüfung überleben.
Standarddifferenziert Granger, zum Vergleich
Die Basislinie, mit der der Vergleich verglichen wird – Log-Returns, gleiche Paare, gleiche BIC-Verzögerung:
from statsmodels.tsa.stattools import grangercausalitytests
def differenced_granger(data, target, predictor, p):
"""Standard Granger test on log-returns at a fixed lag p."""
pair = data[[target, predictor]].dropna() # returns, not levels
out = grangercausalitytests(pair, maxlag=[p]) # statsmodels >= 0.15
f_stat, p_value = out[p][0]["ssr_ftest"][:2]
return {"target": target, "predictor": predictor, "lag": p,
"f_stat": f_stat, "p_value": p_value}
Notiz maxlag=[p] statt maxlag=p: Durch die Übergabe eines Int wird jede Verzögerung von 1 bis ausgeführt und verleitet Sie dazu, den besten Test zu melden, bei dem es sich um einen nicht protokollierten Mehrfachtest zusätzlich zu dem Mehrfachtest handelt, den Sie bereits ausführen.
Der Vergleich
Führen Sie für jedes Paar den differenzierten Test auf Renditen und den Toda-Yamamoto-Test auf Ebenen mit demselben BIC-Auswahlwert durch , und tabellieren Sie, wo die beiden nicht übereinstimmen. Uneinigkeit ist die interessante Zelle: Ein Paar, das hinsichtlich der Unterschiede, aber nicht hinsichtlich der Ebenen signifikant ist, ist ein mögliches Artefakt für die Differenzierung einer kointegrierenden Beziehung; Das Gegenteil deutet darauf hin, dass die Ebenenbeziehung Informationen enthält, die der Rückgabetest nicht sehen kann.
Mehrere Vergleiche auf einer Kausalitätsmatrix

Das volle In der Matrix wird es gefährlich. Ein 20-Asset-, 10-Lag-Sweep ergibt 3.800 Hypothesentests, und Bonferroni ist die falsche Korrektur für eine Familie, die so korreliert – die Tests teilen sich Daten, teilen sich den BTC-Faktor und sind bei weitem nicht unabhängig, sodass Bonferroni gleichzeitig insgesamt zu konservativ ist und irreführend hinsichtlich der Frage, welche Zellen überleben. Verwenden Sie die effektive N-Maschinerie aus dem deflationierten Sharpe-Artikel, die genau für diese Situation entwickelt wurde: Clustern Sie die korrelierte Testfamilie, zählen Sie unabhängige Versuche anstelle von Rohversuchen und legen Sie den Schwellenwert dagegen fest.
def granger_matrix(data, max_lag=15, d_max=1):
"""Toda-Yamamoto p-value matrix. Entry (i, j): does col_j cause col_i?"""
cols = list(data.columns)
out = pd.DataFrame(np.nan, index=cols, columns=cols, dtype=float)
for target in cols:
for predictor in cols:
if target == predictor:
continue
r = toda_yamamoto_test(data, target, predictor,
max_lag=max_lag, d_max=d_max)
out.loc[target, predictor] = r["p_value"]
return out
Die Zahl, die zählt, ist nicht, wie viele Zellen unter 0,05 liegen, sondern wie viele den korrigierten Schwellenwert für effektives N überleben.
Lesen Sie die erhaltene Matrix strukturell und nicht Zelle für Zelle: Zeilen, in denen ein Vermögenswert viele andere verursacht, bestätigen eine Informationshierarchie; Eine durch nichts verursachte Kolumne deutet eher auf eine eigenwillige, tokenspezifische Dynamik als auf eine Entdeckung hin.
Der ehrliche Test: Rollstabilität

Ein einzelner p-Wert in der Stichprobe ist für den Handel nahezu wertlos. Die relevante Frage ist, ob die Bedeutung anhält. Asset-übergreifende Beziehungen in Krypto sind vom Regime abhängig – die Korrelationsstruktur unterscheidet sich stark zwischen Ruhe und Panik, und das Regime selbst ist schätzbar (HMM-Regimeerkennung) – eine über ein Fenster geschätzte Lead-Lag ist also eine Aussage über dieses Fenster.
def rolling_granger(data, target, predictor, window=500, lag=5, step=50):
"""Rolling-window p-value: when is the lead-lag active vs dormant?"""
rows = []
for start in range(0, len(data) - window, step):
chunk = data.iloc[start:start + window][[target, predictor]].dropna()
if len(chunk) < window * 0.8:
continue
try:
out = grangercausalitytests(chunk, maxlag=[lag])
f_stat, p_value = out[lag][0]["ssr_ftest"][:2]
except Exception:
f_stat, p_value = np.nan, np.nan
rows.append({"timestamp": data.index[start + window - 1],
"f_stat": f_stat, "p_value": p_value})
return pd.DataFrame(rows).set_index("timestamp")
Melden Sie zwei Dinge aus dieser Serie: den Anteil der Fenster unter 0,05 und die Anzahl der Schwellenwertüberschreitungen. Eine Beziehung, die in 80 % der Fenster mit drei Kreuzungen signifikant ist, ist ein anderes Objekt als eine Beziehung, die in 55 % der Fenster mit vierzig Kreuzungen signifikant ist, selbst wenn der gepoolte p-Wert identisch ist. Das zweite ist nicht handelbar – Sie können die Positionsgröße nicht anhand eines Signals bestimmen, dessen Existenz sich alle paar hundert Balken ändert, und die Neuschätzungsverzögerung garantiert, dass Sie immer mit dem vorherigen Regime handeln.
Die Datenfalle, die speziell für Granger gilt

Die Hygiene allgemeiner Kryptodaten wird an anderer Stelle behandelt – Lücken und fehlende Kerzen in Backtest-Live-Parität, Zeitstempeldisziplin in der Look-ahead-Bias-Taxonomie und Beweis keine Vorausschau über Zeitrahmen hinweg. Ein Fehlermodus ist jedoch Granger-spezifisch und schwerwiegend genug, um ihn zu nennen:
Vorwärtsfüllung erzeugt das Ergebnis. Eine vorwärtsgefüllte Kerze wiederholt den vorherigen Schluss, wodurch reine Autokorrelation in die Serie eingefügt wird – und Lag-1-Autokorrelation in das mechanisch ausgerichtet ist ist für den F-Test nicht von einem Kausalzusammenhang mit einer Verzögerung zu unterscheiden. Dasselbe gilt für alle Veranstaltungsorte: Ein 1-Sekunden-Uhrzeitversatz zwischen zwei Wechseln auf Minutenbalken kann die Bedeutung von Lag-1 erzeugen oder zerstören, da dadurch verschoben wird, auf welcher Seite der Balkengrenze ein Zug landet. Bevor Sie dies ausführen, stellen Sie sicher, dass Lücken gelöscht und nicht gefüllt werden und dass beide Serien von derselben Uhr stammen.
In der Literatur über Lead-Lag-Ergebnisse berichtet

Hierbei handelt es sich um Zitate, nicht um Messungen aus diesem Artikel. Sie sind hier, um zu sagen, was in den veröffentlichten Aufzeichnungen behauptet wird, so dass der obige Vergleich einen Grund hat, dem man zustimmen oder nicht zustimmen kann.
- BTC zu Altcoins. Eine Studie aus dem Jahr 2026 in Asia-Pacific Financial Markets (Springer) berichtet über eine hochfrequente Preisübertragung von Bitcoin auf Altcoins, wobei Small-Cap-Coins deutlich verzögerte Reaktionen und eine geringere Liquidität im Zusammenhang mit langsameren Reaktionen zeigen. Die in diesem Bereich häufig zitierten Verzögerungsgrößen – etwa 1–3 Minuten von BTC zu ETH, länger für Mid- und Small-Caps, zunehmend unidirektional, wenn die Marktkapitalisierung sinkt – sind zitierte Ergebnisse, die hier nicht erneut abgeleitet werden. Die Marktkapitalisierungsstufe, auf der sie basieren, ist dieselbe Leiter, die bei der [Multi-Symbol-Validierung] (/en/blog/post/multi-symbol-validation) verwendet wird.
- CEX führt DEX an. Forschung zur Krypto-Mikrostruktur (MDPI) berichtet, dass zentralisierte Handelsplätze die Preisermittlung dominieren, wobei der Informationsfluss von CEX zu DEX läuft und keine signifikante umgekehrte Kausalität besteht – im Einklang mit Matching-Engines im Submillisekundenbereich im Vergleich zur Blockzeitabwicklung.
- ETH als unabhängige Münze. VAR-SVAR-Arbeit (MDPI) findet Regime, in denen Ethereum als Quelle und Bitcoin als Spillover-Empfänger fungiert, insbesondere in DeFi- und NFT-gesteuerten Phasen.
Cross-Exchange, kurz
Die Verzögerung bei gleicher Münze und zwei Handelsplätzen ist ein echtes Setup, aber die Wirtschaftlichkeit davon – Gebührenschwellenwerte, die Latenzleiter, warum die Verzögerung überhaupt existiert – wurde bereits in statistische Arbitrage und Paarhandel und die Kimchi-Prämie durchgearbeitet. Das Einzige, was Granger hinzufügt, ist eine Stabilitätsfrage: Ist die Kausalität zwischen Binance und Coinbase anhaltend signifikant oder flackert sie wie alles andere? Führen Sie den Rolling-Test für das Veranstaltungsortpaar durch. Die Antwort ist eine p-Wert-Zeitreihe, kein Ja.
Eine überlebende Verzögerung in eine Position verwandeln

Wenn ein Paar den korrigierten Schwellenwert und den Rolltest überwindet, ist das Signal selbst trivial: kumulative Prädiktorrückgabe über das Verzögerungsfenster, mit Schwellenwert.
def lead_lag_signal(btc_returns, alt_returns, lag=5, threshold=0.001):
"""+1 / -1 / 0 on ALT from BTC's cumulative return over `lag` bars."""
btc_cum = btc_returns.rolling(lag).sum()
signal = pd.Series(0, index=alt_returns.index)
signal[btc_cum > threshold] = 1
signal[btc_cum < -threshold] = -1
return signal
Drei Dinge, die nicht Teil dieses Artikels sind, weil sie hier bereits geregelt sind:
- Die Kosten entscheiden darüber. Ein winziges Verzögerungssignal bei Altcoins muss Spread, Auswirkungen und Gebühren klären – siehe Slippage- und Kostenmodelle und Maker-Taker-Ökonomie und Was passiert, wenn Kosten auf eine Auswahl angewendet werden Gewinner.
- Die Größenbestimmung ist keine p-Wert-Transformation. Die umgekehrte Skalierung der Belichtung mit dem Granger-p-Wert ist falsch: Ein p-Wert ist ein Beweis gegen eine Null, keine Effektgröße, und er ändert sich mit der Stichprobenlänge. Größe des geschätzten Effekts und seiner Unsicherheit – siehe Kelly-Größe.
- Die Validierung erfolgt schrittweise. Führen Sie eine fortlaufende Neuschätzung durch und bewerten Sie außerhalb der Stichprobe. Walk-Forward-Optimierung ist das Protokoll.
Einschränkungen

Granger-Kausalität ist keine Kausalität. Confounder (ein Makroereignis, das beide Beine mit leichter Zeitstempel-Fehlausrichtung bewegt), gemeinsame Treiber (zwei Alts, die beide BTC mit unterschiedlichen Geschwindigkeiten folgen) und ausgelassene Variablen (Testen von BTC zu DOGE ohne ETH im System) erzeugen alle signifikante Statistiken ohne direkten Informationsfluss. Die Beschränkung auf bivariate Tests, wie es in diesem Artikel der Fall ist, verschlimmert das Problem der ausgelassenen Variablen, nicht besser.
Linearität. Der Test erkennt im bedingten Mittel nur eine lineare Vorhersagestruktur. Krypto weist Volatilitätscluster, Hebeleffekte und Regimewechsel auf – siehe GARCH-Volatilitätsprognose und DCC-GARCH dynamische Korrelation für die Geschichte des zweiten Moments. Wissenswerte nichtlineare Alternativen: der Kerneltest von Diks-Panchenko (2006), Transferentropie als informationstheoretisches Analogon und Copula-Granger-Kausalität über die gesamte gemeinsame Verteilung.
Strukturelle Brüche. Jede in einem Fenster geschätzte Beziehung ist vom Regime dieses Fensters abhängig. Der obige fortlaufende Test stellt die Mindestdiagnose dar und ist eine Diagnose, keine Lösung.
Zusammenfassung

- Passen Sie den VAR an Ebenen an und wählen Sie aus um BIC pro Paar, erhöhen um , und Wald-Test der erste nur Verzögerungen. Erstellen Sie die Restriktionsmatrix von Hand – die der Bibliothek
test_causalityschränkt auch die Vergrößerungsverzögerung ein, was nicht Toda-Yamamoto ist. - Führen Sie den differenzierten Rückgabetest als Basis für dieselben Paare und Verzögerungen durch und melden Sie die Unstimmigkeiten. Diese Tabelle ist das Ergebnis; Eine Matrix aus Sternchen ist es nicht.
- Korrigieren Sie die Matrix für eine korrelierte Testfamilie über effektives N, nicht über Bonferroni, und geben Sie an, wie viele Zellen überleben.
- Rollen Sie es. Geben Sie den Anteil der signifikanten Fenster und die Anzahl der Kreuzungen an. Die Bedeutung des Flackerns ist keine handelbare Verzögerung, egal wie klein der gepoolte p-Wert ist.
- Schließen Sie Lücken, anstatt sie nach vorne zu füllen, und überprüfen Sie die Ausrichtung der Uhren an allen Veranstaltungsorten, bevor Sie an ein Lag-1-Ergebnis glauben.
Ein vollkommen gutes Ergebnis dieses Verfahrens ist negativ – eine BTC-zu-Alt-Beziehung, die in der Stichprobe signifikant ist, die Korrektur übersteht und immer noch alle paar hundert Balken die 0,05-Linie in beide Richtungen überschreitet, ist ein echtes Ergebnis in Bezug auf die Handelbarkeit und es lohnt sich, als solches veröffentlicht zu werden.
Referenzen
- Granger, C.W.J. (1969). „Untersuchung kausaler Zusammenhänge durch ökonometrische Modelle und spektrale Methoden.“ Econmetrica, 37(3), 424-438.
- Toda, H.Y. und Yamamoto, T. (1995). „Statistische Inferenz in Vektorautoregressionen mit möglicherweise integrierten Prozessen.“ Journal of Econmetrics, 66(1-2), 225-250.
- Diks, C. und Panchenko, V. (2006). „Eine neue Statistik und praktische Richtlinien für nichtparametrische Granger-Kausalitätstests.“ Journal of Economic Dynamics and Control, 30(9-10), 1647-1669.
- Sifat, I.M., Mohamad, A. (2019). „Lead-Lag-Beziehung zwischen Bitcoin und Ethereum: Belege aus stündlichen und täglichen Daten.“ Research in International Business and Finance, 50, 306-321.
- „Preisübertragung von Bitcoin zu Altcoins: Hochfrequenzbeweise und Implikationen für die Handelsstrategie.“ Asia-Pacific Financial Markets, Springer, 2026.
- „Spillover-Risiken auf Kryptowährungsmärkten: Ein Blick aus der VAR-SVAR-Granger-Kausalität.“ Journal of Risk and Financial Management, MDPI.
- „Die zweistufige Struktur der Märkte für Kryptowährungsfinanzierungszinsen.“ Mathematik, MDPI.
- "Dezentraler und zentraler Austausch: Welche digitalen Token bergen ein größeres Ansteckungsrisiko?" ScienceDirect, 2023.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.