Model Pruning for Low-Latency Trading Inference
Unser DeepLOB-Artikel beendet seinen Bereitstellungsabschnitt mit drei Aufzählungszeichen – ONNX plus TensorRT, INT8-Quantisierung, FPGA – und behandelt keine davon. Dieser Artikel ist die fehlende Behandlung des ersten Problems unter allen dreien: Das Modell ist größer als es sein muss. Durch die Bereinigung neuronaler Netzwerke werden redundante Parameter entfernt, und die interessante Behauptung in der Literatur lautet nicht, dass dadurch Speicher gespart wird, sondern dass ein Subnetzwerk, das 10–20 % der Gewichte enthält, mit der Genauigkeit des dichten Modells mithalten kann.
Dass die Latenz überhaupt eine Rolle spielt, hat der Blog bereits dargelegt – ZigBolt auf dem Messaging-Pfad und die IPC-Steuer mit der Break-Even-Arithmetik – und Spread Modeling besitzt bereits die Schnell-aber-etwas-schlechter versus langsam-aber-besserer Kompromiss, komplett mit einer Gradient-Boosting- versus Deep-Learning-Tabelle, die eine Inferenzlatenzzeile enthält. Was keiner von ihnen abdeckt, ist, wie man ein bestimmtes Modell verkleinert. Von den Phasen einer Zitatschleife unterliegt die Modellinferenz vollständig unserer Kontrolle; Die Transportstrecken werden mit reproduzierbaren p50/p95/p99-Nummern in Datenkommunikation für Algotrading abgedeckt.
Was dieser Artikel ist: der Mathematik- und Arbeitscode für Magnitude Pruning, Structured Pruning, Iterative Magnitude Pruning, Movement Pruning, Knowledge Destillation und NVIDIA 2:4 Semi-Structured Sparsity, angewendet auf ein Trading-MLP.
Was es nicht ist: ein gemessenes Ergebnis. Jeder empirische Artikel in diesem Blog trägt eine Provenienzlinie oder ein begleitendes Repo, und dieser trägt noch keines von beiden. Die Sparsity-versus-Genauigkeit-versus-Latenz-Kurve wird unten als Experiment zur Durchführung und nicht als Tabelle zum Zitieren angegeben. Behandeln Sie hier alles als Methode und die Zahlen als ausstehend.
Was Sie durch Beschneiden gewinnen

Die Einschränkung ist eine Größe eins. Betrachten Sie ein Mittelfrequenzmodell – ein 4-Schicht-MLP mit 2048 versteckten Einheiten über den Orderbuchfunktionen:
Für , , , , das sind ungefähr 12,6 Millionen Parameter – ungefähr 48 MB in float32. L2 ist normalerweise 1–4 MB groß, daher passen die Gewichtungen nicht; Sie werden bei jedem Vorwärtsdurchgang von weiter außen gestreamt. Wenn Sie 95 % davon bereinigen, haben Sie etwa 630 KB effektive Parameter und 2,4 MB, was durchaus passt.
Ob sich das auf die Arbeitszeit übertragen lässt, hängt davon ab, ob der Kernel speichergebunden ist, und das ist eher eine Frage der arithmetischen Intensität als eine Frage der Größe. Die Backtest-Motorgeschwindigkeitsleiter arbeitet das Dachlinienmodell (Williams, Waterman & Patterson) anhand eines gemessenen Beispiels, anstatt einen Straffaktor geltend zu machen; Hier gilt der gleiche Rahmen und die gleiche Disziplin: Messen Sie die verschobenen Bytes, bevor Sie die Beschleunigung in Anspruch nehmen.
Grundlagen des Beschneidens

Unstrukturierter Schnitt
Der einfachste Ansatz: Setzen Sie einzelne Gewichte basierend auf ihrer Größe auf Null. Gegeben sei eine Gewichtsmatrix , erstellen Sie eine Binärmaske so dass:
Wo ist ein Schwellenwert, der gewählt wird, um das gewünschte Sparsity-Niveau zu erreichen :
Die beschnittene Matrix ist , mit das Hadamard-Produkt. Die Intuition ist, dass Gewichte nahe Null wenig zur Ausgabe der Ebene beitragen.
Das Problem wird klar formuliert, weil es leicht ist, die Sparsity-Zahl falsch zu interpretieren: Unstrukturierte Sparsity führt nicht zu einer Beschleunigung auf Standardhardware. Eine Matrix mit 90 % Nullen gibt immer noch die gleiche Anzahl von Multiplikations-Akkumulierungen aus, es sei denn, Sie wechseln zu Sparse-Kerneln oder Hardware mit Sparsity-Unterstützung. Wenn der folgende Code gedruckt wird Sparsity: 90.0%, das ist eine Zählung von Nullen – es ist kein 10-faches, und auf einem GEMM mit dichter CPU ist es auch kein 1,01-faches. Die Pfade, die Zeit sparen, sind strukturiertes Pruning (kleinere Matrizen) und 2:4 halbstrukturierte Sparsity (Hardware-Unterstützung), beide unten.
Strukturierter Schnitt
Beim strukturierten Beschneiden werden ganze Neuronen, Kanäle oder Aufmerksamkeitsköpfe entfernt. Für eine lineare Ebene mit , Neuron entfernen setzt das auf Null -te Reihe von und die -tes Element von :
Neuronen mit den kleinsten -Norm geht zuerst. Dies ist die Variante, die wirklich kleinere Matrizen erzeugt – allerdings nur, wenn man die Schichten tatsächlich neu aufbaut. Das Nullen von Zeilen und das Belassen des Tensors in seiner ursprünglichen Form ändert nichts an der FLOP-Anzahl; Der Neuerstellungsschritt im Implementierungsabschnitt konvertiert die Maske in eine Matrix.
Für Faltungsschichten ist das Analogon die Filterbereinigung. Gegeben , die Bedeutung des Ausgabefilters Ist:
Filter entfernen eliminiert einen gesamten Ausgangskanal und reduziert die FLOPs proportional.
Die Lottoschein-Hypothese

Im Jahr 2019 führten Frankle und Carbin die Lottery Ticket Hypothesis (LTH) ein: Innerhalb eines zufällig initialisierten dichten Netzwerks gibt es ein spärliches Teilnetzwerk – ein „Gewinnlos“ – das, trainiert von seiner ursprünglichen Initialisierung, in einer vergleichbaren Anzahl von Iterationen mit der Genauigkeit des gesamten Netzwerks übereinstimmt.
Überlegen Sie formal initialisiert mit . Nach dem Training zur Konvergenz erhalten wir und leiten Sie eine Schnittmaske ab . Das LTH gibt an, dass es existiert so dass:
mit . Die ursprünglichen Experimente erfolgten mit MNIST und CIFAR-10, wobei die Gewinnscheine 10–20 % der Parameter behielten. Nichts davon lässt sich aufgrund der Annahme auf Orderbuchdaten übertragen – LOB-Merkmale sind instationär und die Bezeichnung ist nahezu verrauscht, was sich in genau den Punkten, die wichtig sein könnten, von der Bildklassifizierung unterscheidet.
Iterative Magnitude Pruning (IMP)
Das Ticket wird von IMP gefunden:
- Initialisieren Sie das Netzwerk mit .
- Konvergenz trainieren, erhalten .
- Beschneiden Sie die von Gewichten mit kleinster Größe, wodurch eine Maske entsteht .
- Setzen Sie die verbleibenden Gewichte auf ihre Werte in zurück (zurückspulen).
- Wiederholen Sie ab Schritt 2 mit dem maskierten Netzwerk.
Jede Runde schneidet einen Teil ab (normalerweise 20 %), also danach Runden der Parameter überleben. Nach 10 Runden bei verbleiben etwa 10,7 %.
Drei Hypothesen über Handelsmodelle, keine davon getestet
Es ist verlockend zu argumentieren, dass LTH bei Marktdaten besonders gut funktionieren sollte. Es tauchen drei solcher Argumente auf; Bei allen dreien handelt es sich um Hypothesen, und sie als Fakten darzustellen, ist der Fehlermodus, den dieser Blog vermeiden möchte.
- Finanzsignale sind spärlich. Der größte Teil eines Orderbuch-Snapshots besteht aus Rauschen, daher kann ein spärliches Subnetzwerk auf natürliche Weise mit einem spärlichen Signal übereinstimmen. Testbar: IMP mit einer Zufallsmaske gleicher Sparsity vergleichen; Wenn Sparsity selbst die Arbeit erledigt, sollte die Zufallsmaske nicht weit dahinter liegen.
- Gewinnlose Tickets verallgemeinern sich über alle Regime hinweg. Dies ist eine empirische Behauptung über Märkte ohne Quellenangabe und die interessanteste der drei. Es ist direkt anhand der Regimebezeichnungen von Regimeerkennung mit HMMs testbar: Finden Sie das Ticket in Regime A, trainieren Sie es in Regime B neu und vergleichen Sie es mit einem Ticket, das nativ in B gefunden wurde.
- Sparsity reguliert. Eine geringere effektive Kapazität kann die Anpassung an Mikrostrukturrauschen verringern – was sich darin zeigen würde, dass die Out-of-Sample-Lücke des bereinigten Modells kleiner als die des dichten Modells und nicht nur vergleichbar ist.
Implementierung: Beschneiden eines Trading-MLP

Das Basismodell
import torch
import torch.nn as nn
import torch.nn.utils.prune as prune
from copy import deepcopy
class TradingMLP(nn.Module):
"""MLP for mid-price direction prediction from order book features."""
def __init__(self, input_dim=100, hidden_dim=2048,
num_layers=4, output_dim=3):
super().__init__()
layers = []
dims = [input_dim] + [hidden_dim] * (num_layers - 1) + [output_dim]
for i in range(len(dims) - 1):
layers.append(nn.Linear(dims[i], dims[i + 1]))
if i < len(dims) - 2:
layers.append(nn.BatchNorm1d(dims[i + 1]))
layers.append(nn.ReLU())
layers.append(nn.Dropout(0.1))
self.network = nn.Sequential(*layers)
def forward(self, x):
return self.network(x)
def count_parameters(self):
return sum(p.numel() for p in self.parameters())
model = TradingMLP(input_dim=100, hidden_dim=2048,
num_layers=4, output_dim=3)
print(f"Total parameters: {model.count_parameters():,}")
Unstrukturierter Größenschnitt
def apply_unstructured_pruning(model, sparsity=0.9):
"""Apply global unstructured L1 pruning to all Linear layers."""
parameters_to_prune = []
for name, module in model.named_modules():
if isinstance(module, nn.Linear):
parameters_to_prune.append((module, 'weight'))
prune.global_unstructured(
parameters_to_prune,
pruning_method=prune.L1Unstructured,
amount=sparsity,
)
return model
def compute_sparsity(model):
"""Fraction of zero weights. Note: a *count*, not a speedup."""
total, zeros = 0, 0
for name, param in model.named_parameters():
if 'weight' in name:
total += param.numel()
zeros += (param == 0).sum().item()
return zeros / total if total > 0 else 0
pruned_model = apply_unstructured_pruning(deepcopy(model), sparsity=0.9)
print(f"Sparsity: {compute_sparsity(pruned_model):.1%}")
Strukturierter Schnitt, mit dem Umbau, der ihn Wirklichkeit werden lässt
Das Maskieren von Zeilen ist die halbe Arbeit. Die Hälfte, die die Beschleunigung erzeugt, baut jede Schicht in ihrer reduzierten Form wieder auf – was bedeutet, dass sich die Entfernung nach vorne ausbreitet: Zeile fallen lassen der Schicht löscht auch die Spalte der Schicht und Kanal von irgendjemandem BatchNorm1d zwischen ihnen.
def apply_structured_pruning(model, fraction=0.75):
"""Mask entire neurons by L2-norm of their weight rows."""
for name, module in model.named_modules():
if isinstance(module, nn.Linear) and module.out_features > 10:
prune.ln_structured(
module, name='weight', amount=fraction, n=2, dim=0
)
return model
def rebuild_pruned_mlp(model):
"""
Physically shrink a structurally pruned TradingMLP.
Walks the Sequential once. For each Linear: drop the input columns
the previous layer no longer emits, then drop its own dead output
rows. BatchNorm1d channels follow the preceding Linear's survivors.
"""
new_layers = []
keep_in = None # surviving output indices of the previous Linear
for layer in model.network:
if isinstance(layer, nn.Linear):
if prune.is_pruned(layer):
prune.remove(layer, 'weight')
W, b = layer.weight.data, layer.bias.data
keep_out = (W.norm(dim=1) > 0).nonzero(as_tuple=True)[0]
W = W[keep_out]
if keep_in is not None:
W = W[:, keep_in]
new = nn.Linear(W.shape[1], W.shape[0])
new.weight.data = W.clone()
new.bias.data = b[keep_out].clone()
new_layers.append(new)
keep_in = keep_out
elif isinstance(layer, nn.BatchNorm1d):
new = nn.BatchNorm1d(len(keep_in))
new.weight.data = layer.weight.data[keep_in].clone()
new.bias.data = layer.bias.data[keep_in].clone()
new.running_mean = layer.running_mean[keep_in].clone()
new.running_var = layer.running_var[keep_in].clone()
new.num_batches_tracked = layer.num_batches_tracked.clone()
new_layers.append(new)
else: # ReLU, Dropout -- shape-agnostic, reuse as is
new_layers.append(layer)
rebuilt = deepcopy(model)
rebuilt.network = nn.Sequential(*new_layers)
return rebuilt
Bevor Sie dem vertrauen, sollten Sie zwei Dinge überprüfen, ganz im Sinne der Äquivalenz-Gates, die auch im Rest des Blogs ausgeführt werden:
- Formen.
rebuiltsollte versteckte Dimensionen anzeigen — 512 fürfraction=0.75, – und eine Parameteranzahl, die quadratisch gesunken ist, da beide Dimensionen der inneren Matrizen schrumpfen. - Ausgänge. In
eval()Modus,rebuilt(x)muss mit dem maskierten Modell übereinstimmenrebuilt-freie Ausgabe mit Gleitkommatoleranz für denselben Stapel. Ist dies nicht der Fall, ist die Spaltenweitergabe falsch und jede Downstream-Zahl misst ein anderes Modell als Sie denken.
Beim Zeilenüberlebenstest wird davon ausgegangen, dass eine maskierte Zeile genau Null ist, eine aktive Zeile jedoch nicht. Das gilt für ln_structured Ausgabe; Dies würde nicht gelten, wenn ein anderes Verfahren ein echtes lebendes Neuron mit nur Nullen erzeugen würde. Stellen Sie daher die Anzahl der Überlebenden anhand des angeforderten Bruchteils fest, anstatt dem Normtest blind zu vertrauen.
Iterative Größenbeschneidung (Lottoscheinsuche)
def lottery_ticket_search(model_cls, model_kwargs, train_fn, eval_fn,
rounds=10, prune_rate=0.2, device='cpu'):
"""
Iterative Magnitude Pruning to find a winning ticket.
Parameters
----------
model_cls : class -- model constructor
model_kwargs : dict -- constructor arguments
train_fn : callable -- train_fn(model) trains the model in-place
eval_fn : callable -- eval_fn(model) returns out-of-sample accuracy
rounds : int -- number of pruning rounds
prune_rate : float -- fraction of surviving weights pruned per round
"""
model_init = model_cls(**model_kwargs).to(device)
theta_0 = deepcopy(model_init.state_dict())
mask = {}
for name, param in model_init.named_parameters():
if 'weight' in name:
mask[name] = torch.ones_like(param, dtype=torch.bool)
results = []
for round_idx in range(rounds):
model = model_cls(**model_kwargs).to(device)
state = deepcopy(theta_0)
for name in mask:
state[name] = state[name] * mask[name].float()
model.load_state_dict(state)
train_fn(model)
acc = eval_fn(model)
surviving = sum(m.sum().item() for m in mask.values())
total = sum(m.numel() for m in mask.values())
sparsity = 1.0 - surviving / total
results.append({
'round': round_idx,
'accuracy': acc,
'sparsity': sparsity,
'surviving_params': int(surviving)
})
print(f"Round {round_idx}: acc={acc:.4f}, "
f"sparsity={sparsity:.1%}")
all_weights = []
for name, param in model.named_parameters():
if name in mask:
alive = param.data.abs()[mask[name]]
all_weights.append(alive.flatten())
all_weights = torch.cat(all_weights)
k = int(len(all_weights) * prune_rate)
if k == 0:
break
threshold = all_weights.kthvalue(k).values.item()
for name, param in model.named_parameters():
if name in mask:
mask[name] = mask[name] & (
param.data.abs() >= threshold
)
return results, mask
results ist das Rohmaterial für die Sparsitäts-Genauigkeits-Kurve, die Ihnen dieser Artikel schuldet. eval_fn muss bei bereinigten Splits tatsächlich außerhalb der Stichprobe liegen – ein in der Stichprobe erzielter IMP-Lauf zeigt eine schöne Kurve, die nichts bedeutet.
Messen

Die Latenz wird mit der gleichen Konvention wie im Rest des Blogs gemessen – Aufwärmen ausgeschlossen, Best-of-N, p50/p95/p99 statt eines Mittelwerts – und dieses Protokoll mit dem Code befindet sich in Polars vs Pandas. Drei Besonderheiten beim Beschneiden:
- Vergleichen Sie das neu erstellte Modell, nicht das maskierte. Ein maskiertes Modell mit Losgröße 1 misst die dichte Form.
- Geben Sie die Chargengröße an. Batch 1 (Quoting-Schleife) und Batch 256 (Recherche-Sweep) befinden sich auf unterschiedlichen Seiten der speichergebundenen/rechengebundenen Linie, und das Beschneiden hilft ihnen unterschiedlich.
- Berichten Sie über die Genauigkeit für denselben Split, denselben Horizont und die angegebene Label-Definition. Eine Latenztabelle ohne die Spalte „Matching Accuracy“ ist ein Argument dafür, das Modell vollständig zu löschen.
Fortgeschrittene Techniken

Beschneiden mit Wissensdestillation
Anstatt isoliert zu beschneiden und zu verfeinern, nutzen Sie das ursprüngliche dichte Modell als Lehrmittel. Der beschnittene Schüler minimiert eine Kombination aus Aufgabenverlust und der KL-Abweichung von der Ausgabeverteilung des Lehrers:
Wo Und sind Lehrer- und Schülerlogs, ist die Temperatur und gleicht die Ziele aus. Der Faktor skaliert die Destillationsgradienten neu, die sonst schrumpfen würden .
def distillation_loss(student_logits, teacher_logits, labels,
temperature=3.0, alpha=0.5):
"""Combined task + distillation loss."""
task_loss = nn.CrossEntropyLoss()(student_logits, labels)
soft_student = nn.functional.log_softmax(
student_logits / temperature, dim=-1
)
soft_teacher = nn.functional.softmax(
teacher_logits / temperature, dim=-1
)
kd_loss = nn.functional.kl_div(
soft_student, soft_teacher, reduction='batchmean'
)
return (1 - alpha) * task_loss + alpha * (temperature ** 2) * kd_loss
Bewegungsbeschneidung
Anstatt nach der absoluten Größe zu beschneiden, werden beim Bewegungsbeschneiden (Sanh et al., 2020) Gewichte beschnitten, die sich während des Trainings in Richtung Null bewegen. Der Wichtigkeitswert akkumuliert das Gradienten-Gewichts-Produkt:
Gewichtungen mit negativen Werten werden bereinigt. Das Argument dafür gegenüber der Magnitudenbeschneidung bezieht sich insbesondere auf die Feinabstimmung: Wenn Sie ein vorab trainiertes Modell anpassen, wurde die Magnitudenverteilung durch die vorab trainierte Aufgabe geformt, sodass die Magnitude ein veraltetes Wichtigkeitssignal und die Bewegungsrichtung ein frischeres Signal ist. Bei einem Handelsmodell, das auf rollierende Fenster umgeschult wird, ist dies die häufigere Situation als das Training von Grund auf.
NVIDIA 2:4 Strukturierte Sparsity
Ampere- und neuere NVIDIA-GPUs unterstützen 2:4 strukturierte Sparsity in der Hardware: Von jeweils 4 zusammenhängenden Gewichtungen müssen genau 2 Null sein.
Dies ist die einzige Form der feinkörnigen Sparsität, die von der Hardware tatsächlich belohnt wird, weshalb sie wichtiger ist als die 90 %-Nullen-Zahl aus unstrukturiertem Pruning. Die Einschränkung ist eher lokal als global – es ist egal, welche von jeweils vier überleben – es handelt sich also um eine viel schwächere Einschränkung als die Festlegung einer globalen Maske, obwohl 50 % die einzige angebotene Sparsity-Stufe ist.
from torch.ao.pruning import WeightNormSparsifier
sparsifier = WeightNormSparsifier(
sparsity_level=0.5,
sparse_block_shape=(1, 4),
zeros_per_block=2,
)
sparsifier.prepare(
model, config=[{"tensor_fqn": "network.0.weight"}]
)
sparsifier.step()
sparsifier.squash_mask()
Um die Beschleunigung zu realisieren, muss der Inferenzpfad die spärlichen Tensorkerne verwenden – einen ONNX-Export plus TensorRT-Build, oder torch.sparse.to_sparse_semi_structured. Wenn Sie ein 2:4-maskiertes Modell über eine dichte Laufzeit exportieren, erhalten Sie den Genauigkeitsaufwand, aber keinen Nutzen.
Produktionsbereitstellung

Validierung
Ein beschnittenes Modell ist ein neues Modell, kein komprimiertes altes, und es durchläuft dasselbe Akzeptanztor wie jeder andere Kandidat: rollierendes Neutraining und Out-of-Sample-Revalidierung gemäß Walk-Forward-Optimierung mit der Auswahleffektkorrektur aus der deflationierten Sharpe-Ratio. Diese Korrektur ist hier nicht optional – IMP generiert eine Sequenz von Kandidatenmodellen, daher wurde bei der Suche der Sparsity-Level ausgewählt, der über zehn Runden am besten aussieht, und sein Sharpe muss anhand der effektiven Anzahl von Versuchen deflationiert werden. Eine pauschale Regel wie „Ablehnen, wenn Sharpe um mehr als 5 % sinkt“ übersteht diese Arithmetik nicht, weshalb Sie in diesem Artikel keine finden werden.
Quantisierungsstapelung
Beschneiden komponiert mit Quantisierung. Ein zu 90 % dünn besetztes und auf INT8 quantisiertes Modell hat ein Komprimierungsverhältnis von:
Aus einem 48-MB-Modell werden 1,2 MB. Das ist ein Lageranspruch und nichts weiter. Ob das 1,2-MB-Modell zu denselben Entscheidungen führt, ist eine separate Frage mit eigener Antwort, und die GPU-Präzisionsfalle ist der Grund, sie zu stellen: In diesem Blog wurde gezeigt, dass fp32 allein in einer Backtest-Berechnung, die völlig vernünftig aussah, einen relativen Fehler von 211 erzeugte. INT8 ist eine weitaus aggressivere Reduzierung. Versenden Sie ein quantisiertes und bereinigtes Modell nur hinter einem quantifizierten Paritätstor gegenüber dem fp32-dichten Modell – Entscheidungsübereinstimmungsrate und PnL-Delta für einen angehaltenen Zeitraum, keine Zusicherung.
Überwachung
Beschnittene Modelle können empfindlicher auf Verteilungsverschiebungen reagieren. Sehenswert:
- Aktivierungssparsität: Wenn überlebende Neuronen überwiegend Nullen aussenden, ist das effektive Modell kleiner als beabsichtigt und wahrscheinlich degradierend.
- Gradientennormen während der Umschulung: Explodierende Gradienten deuten darauf hin, dass vom überlebenden Teilnetzwerk verlangt wird, zu aggressiv das zu kompensieren, was entfernt wurde.
- Vorhersage-Entropie: Ein beschnittenes Modell, das bei verrauschten Mikrostrukturdaten zu selbstsicher wird, passt wahrscheinlich zum Trainingsprogramm.
Fazit

Die Methoden sind gut etabliert und das ist alles, was dieser Artikel behauptet, bis der Sweep läuft. Durch unstrukturiertes Beschneiden erhalten Sie eine spärliche Zahl und keine Geschwindigkeit. Durch strukturiertes Beschneiden erhalten Sie Geschwindigkeit, wenn – und nur dann – Sie die Ebenen neu aufbauen, anstatt sie zu maskieren. Die Lotterieschein-Hypothese legt nahe, dass das kompakte Modell bereits innerhalb des überparametrisierten Modells existiert, obwohl dies anhand von Bild-Benchmarks und nicht anhand von Orderbuchdaten nachgewiesen wurde, und die drei oben genannten Gründe, warum es bei Marktdaten funktionieren „sollte“, sind Hypothesen mit angehängten Experimenten, keine Erkenntnisse.
Die praktische Heuristik aus der Literatur besteht darin, groß zu trainieren und zu beschneiden, anstatt von Anfang an klein zu entwerfen: Das große Modell untersucht die Verlustlandschaft effektiver, und durch das Beschneiden bleiben die Pfade erhalten, die wichtig sind. Ob dies für ein Handelsmodell gilt, bei welcher Sparsität und bei welchen Genauigkeitskosten, ist nur ein IMP-Durchlauf entfernt – und dieser Artikel sollte nach diesem Durchlauf noch einmal gelesen werden, mit Zahlen darin.
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.