Simulación de fills: la escalera desde la fantasía del precio de cierre hasta la realidad consciente de la cola
Tu backtest contiene dos modelos: un modelo de tu alpha y un modelo de tus fills. La mayoría de la gente dedica el 95% de su esfuerzo al primero y hereda el segundo del framework que le toque usar. Esto está al revés. Una señal mediocre con un modelo de fills honesto produce una estimación de PnL mediocre pero real. Una señal excelente con fill_price = candle.close produce un número que no es una estimación de nada — es el resultado de una suposición que nunca examinaste.
Para estrategias taker sobre instrumentos líquidos, el modelo de fills es un término de corrección. Para cualquier cosa que involucre órdenes límite pasivas — market making, entradas pasivas, captura de rebates post-only — el modelo de fills es la estrategia. Si consigues fill, cuándo, en qué cantidad, y condicional a qué movimiento de precio posterior, determina el signo del PnL, no solo su magnitud.
En Paridad backtest-live mapeamos la taxonomía completa de divergencias entre backtest y live, y calificamos la divergencia de ejecución con severidad 5/5 — la peor clase. Ese artículo dio a la simulación de fills tres niveles de precisión gruesos y siguió adelante. Este es el complemento en profundidad: la escalera completa, peldaño por peldaño, con el ciclo de vida de la orden como máquina de estados, límites de probabilidad de fill que puedes calcular de verdad, y un experimento medido que muestra exactamente en qué punto de la escalera muere una estrategia maker "rentable".
La escalera

Cada peldaño requiere más datos y más código, y cada peldaño elimina un sesgo sistemático específico. Los peldaños están ordenados según lo que hacen mal, no solo según su costo.
Peldaño 0: fill al precio de cierre
fill_price = bar.close
La orden se llena instantáneamente, por completo, al cierre de la vela que generó la señal. La señal se calculó a partir de ese mismo cierre, así que estás operando con datos que no existían cuando se imprimió el precio: look-ahead bias disfrazado de ejecución. Cualquier estrategia con rotación se ve bien aquí.
Peldaño 1: apertura de la siguiente vela
fill_price = next_bar.open
El modelo honesto mínimo para lógica taker sobre velas. La señal se calcula en la vela , el fill ocurre en el primer precio observable de la vela . Esto elimina el look-ahead pero aún asume spread cero, impacto cero, liquidez infinita en el precio de apertura y certeza de fill del 100%. Para órdenes límite degenera en lógica de fill por toque (más adelante veremos por qué eso es veneno).
Peldaño 2: spread + slippage fijo
half_spread = mid * spread_bps / 2e4
slip = mid * slippage_bps / 1e4
fill_price = mid + side * (half_spread + slip) # side: +1 compra, -1 venta
Ahora cada operación taker paga medio spread más una constante calibrada. Este es el primer peldaño en el que una estrategia de alta rotación puede morir en el backtest — que es justamente el objetivo. El error residual: el slippage no es constante. Escala con el tamaño de la orden en relación a la profundidad mostrada y se dispara justo cuando tu estrategia más quiere operar. Un 5 bps fijo es un promedio sobre regímenes; tu estrategia no opera el régimen promedio.
Peldaño 3: recorrido de profundidad L2 para órdenes de mercado
Con snapshots del libro de órdenes dejas de adivinar el slippage y lo calculas. Una compra de mercado de tamaño recorre el lado ask nivel por nivel; el precio de fill es el promedio ponderado por volumen a través de los niveles consumidos:
def depth_walk(levels: list[tuple[float, float]], qty: float) -> tuple[float, float]:
"""levels: [(price, size), ...] sorted best-first. Returns (vwap, filled_qty)."""
remaining, cost = qty, 0.0
for price, size in levels:
take = min(size, remaining)
cost += take * price
remaining -= take
if remaining <= 0:
break
filled = qty - remaining
return (cost / filled if filled > 0 else float("nan"), filled)
Dos correcciones hacen esto sustancialmente más honesto. Primero, latencia: recorre el libro tal como estaba después de tu timestamp de decisión, donde es tu latencia medida entre señal y exchange — el libro que viste no es el libro que golpeaste. Segundo, fills marketable parciales: si la profundidad mostrada dentro de tu precio límite es menor que , el modelo debe devolver un fill parcial y dejar un remanente en reposo, lo cual traslada el problema a la máquina de estados que veremos abajo.
El error residual en el peldaño 3 es el impacto y la reposición: consumes el libro como un objeto estático, pero los libros reales se reponen parcialmente (y las contrapartes reales reaccionan). Para tamaños de clip por debajo de unos pocos puntos porcentuales de la profundidad top-of-book este error es pequeño; para clips más grandes necesitas un modelo de impacto (Almgren-Chriss 2001) superpuesto.
Peldaño 4: fills probabilísticos por posición en cola para órdenes límite
Los peldaños 0-3 responden "a qué precio se llena mi orden agresiva". El peldaño 4 responde la pregunta más difícil: ¿se llena mi orden pasiva siquiera? — y es el único peldaño que puede tasar una estrategia maker. Una orden límite en reposo al precio se llena cuando el volumen negociado acumulado en supera el volumen de cola que estaba por delante de ella. Eso requiere rastrear tu posición en una cola FIFO que no puedes observar directamente.
La maquinaria de estimación de posición en cola — posición inicial, reglas de actualización ante trades vs. cancelaciones, la familia de probabilidad para asignar cancelaciones no observadas — es el primitivo que construimos en La cola dentro del muro. No lo volveré a derivar aquí; el simulador lo consume. Lo que añade el peldaño 4 es la regla de decisión de fill sobre esa estimación, cubierta en la sección de probabilidad de fill más abajo.
Por qué importa este peldaño está cuantificado en la literatura: Moallemi y Yuan (2016), "A Model for Queue Position Valuation in a Limit Order Book," muestran que para instrumentos de tick grande el valor económico de estar al frente de la cola frente a estar al final es comparable al medio spread — el mismo orden de magnitud que todo el edge teórico de una estrategia de market making. Un modelo de fills que ignora la posición en cola no subestima el PnL de un maker; estima el PnL de una estrategia distinta.
Existe un peldaño 5 — simulación completa basada en agentes donde el mercado reacciona a tus órdenes (modelos queue-reactive en el sentido de Huang, Lehalle y Rosenbaum 2015; frameworks multiagente como ABIDES, Byrd et al. 2020). El replay histórico, incluso consciente de la cola, asume que tu orden no cambia nada del comportamiento de los demás. Esa suposición es razonable a tamaño retail y cada vez más incorrecta a medida que tus cotizaciones se convierten en una fracción visible del nivel. El peldaño 5 queda fuera del alcance aquí; conviene saber que la escalera no termina en el 4.
Fills parciales como máquina de estados
Los peldaños 0-2 pueden fingir que una orden es una llamada a función: enviar, obtener precio, listo. A partir del peldaño 3, una orden es un proceso con un ciclo de vida, y el simulador debe modelarla como una máquina de estados o manejará mal, silenciosamente, los casos que más importan.

enum OrderState {
PendingNew, // sent, not yet acked (latency window)
Resting { remaining: f64, q_ahead: f64 }, // in book, queue position estimated
PartialFill { remaining: f64, q_ahead: f64 }, // some qty done, rest still queued
PendingAmend, // amend in flight
PendingCancel, // cancel in flight
Filled,
Canceled { filled_qty: f64 }, // may be partially filled at cancel time
Rejected,
}
Las transiciones cargan la economía:
PendingNew→Resting: la orden se une a la cola detrás de todo lo presente en el momento del ack, no en el momento de la decisión. Tu posición en cola se inicializa con el volumen del nivel a partir de . Los simuladores que inicializan en el momento de la decisión sobreestiman sistemáticamente la prioridad en cola — exactamente por el volumen que llegó durante tu ventana de latencia, que es la mayor parte del volumen durante ráfagas.Resting→PartialFill: un trade en tu nivel mayor que la cola por delante te llena parcialmente. El remanente conserva su posición (ahora al frente de la cola). Los fills parciales no son ruido — son información: que te llenen 0.3 de 1.0 y ver que el precio rebota lejos es un evento de PnL distinto de un fill completo, y el proceso de inventario de un maker se construye a partir de estos fragmentos.Resting→PendingAmend→Resting: la trampa. En prácticamente todos los exchanges de cripto, un amend es un cancel/replace — elcancelReplacede Binance es atómico frente a la doble ejecución pero devuelve un nuevo ID de orden al final de la cola. Incluso los venues con semántica de modificación nativa (CME Globex) preservan la prioridad temporal solo para una disminución de cantidad; un cambio de precio o un aumento de cantidad la hace perder. Así que en el simulador: cualquier amend de precio reseteaq_aheadal volumen completo del nivel actual. Un motor de cotización que se re-pegotea cada 500ms no está "manteniendo una cotización" — está reingresando perpetuamente al final de la cola, y su perfil realista de fills es casi selección adversa pura. Combinado con el resultado de Moallemi-Yuan: re-cotizar tiene un precio, y ese precio es tu posición en cola.PendingCancel→PartialFill→Canceled: las cancelaciones también tienen latencia. En la ventana entre decidir retirar una cotización y que la cancelación llegue al motor de emparejamiento, todavía puedes recibir un fill — y esos fills son los peores que vas a recibir, porque la razón por la que estabas retirando la cotización es que el mercado estaba a punto de arrollarte. Un simulador sin latencia de cancelación elimina precisamente los fills más tóxicos de tu historial.
La máquina de estados es también lo que hace honesta la contabilidad del simulador: las comisiones se acumulan por evento de fill, el inventario se actualiza por evento de fill, y las estadísticas de tiempo en cada estado (cuánto tiempo reposan las órdenes antes de llenarse frente a ser canceladas) se vuelven directamente comparables con los logs en vivo — que es lo que alimenta el bucle de calibración al final.
Probabilidad de fill límite: tres modelos y una banda
Dada una orden en reposo al precio (digamos una bid), ¿cuándo declara el simulador un fill? Tres reglas de decisión, en orden creciente de honestidad:
1. Fill por toque (ingenuo). Se llena si el precio toca tu nivel: . Esta es una regla de tiempo de primer paso (first-passage-time), y su fracaso se midió hace un cuarto de siglo: Lo, MacKinlay y Zhang (2002), "Econometric Models of Limit-Order Executions" (Journal of Financial Economics 65), ajustan modelos de supervivencia a datos reales de órdenes límite y concluyen que las ejecuciones hipotéticas construidas a partir de tiempos de primer paso "son proxies muy pobres de las ejecuciones reales de órdenes límite". El modo de fallo es estructural: cuando el precio toca tu nivel y rebota, el toque consumió el frente de la cola — los traders que cotizaron antes que tú. El fill por toque te otorga sus fills. Peor aún, te otorga exactamente los buenos fills (tocar-y-rebotar es el escenario rentable para un maker), mientras que tu conjunto real de fills está sesgado hacia tocar-y-atravesar — los que sufren selección adversa.
2. Trade-through (banda conservadora). Se llena solo si el precio negocia estrictamente a través de tu nivel: , o en datos de tick, el volumen negociado acumulado en supera el nivel entero. Si el precio negoció a través, toda la cola en fue consumida, así que fuiste llenado sin importar tu posición. Esto nunca te otorga un fill que no habrías obtenido. Su sesgo es la imagen espejo del fill por toque: te niega todo fill donde la cola se agotó hasta tu posición sin penetración completa, y los fills que sí concede son desproporcionadamente los de atravesar (los que sufren selección adversa). Un backtest de maker bajo trade-through es una prueba de estrés, no una estimación.
3. Estimación de agotamiento de cola. Rastrea el volumen negociado acumulado en tu precio a partir del tape de trades y el volumen cancelado inferido de los deltas L2. Tu cola estimada por delante:
donde es el volumen del nivel en el momento de entrada de la orden (con timestamp de ack) y es la fracción de cancelaciones que se asume proviene de delante de ti — el parámetro cuya forma fundamentada (la familia ) se deriva en el artículo de posición en cola. El fill comienza cuando ; tu cantidad llenada es el volumen negociado en exceso de eso, lo cual produce fills parciales de forma natural:
Fijar (todas las cancelaciones por delante de ti) da el borde optimista de este modelo; el borde pesimista. Cuando solo tienes snapshots L2 dispersos y no hay tape de trades a nivel de precio — algo común con feeds de cripto limitados a 100ms — puedes recurrir a un prior basado en modelo: Cont, Stoikov y Talreja (2010), "A Stochastic Model for Order Book Dynamics" (Operations Research 58), modelan cada nivel de precio como una cola de nacimiento-muerte y calculan, mediante transformadas de Laplace, la probabilidad de que una orden en la bid se ejecute antes de que el mid se mueva, condicional a los tamaños de cola actuales. Es un oráculo analítico de probabilidad de fill: crudo en comparación con el replay del tape, mucho mejor que el fill por toque, y suficientemente barato para evaluar dentro de un bucle de backtest en caliente.
La disciplina de la banda
Las tres reglas no son competidoras — son un ordenamiento:
lo cual induce una banda de PnL. Corre cada backtest de maker tres veces y reporta el intervalo:
(la desigualdad superior es aproximada — el fill por toque puede reordenar el ranking de estrategias, no solo inflarlas, porque te entrega fills contrafactualmente buenos). La regla de decisión que se deriva: una estrategia maker solo es desplegable si sobrevive en el borde conservador de la banda, y la banda es suficientemente estrecha como para que la estimación puntual signifique algo. Una estrategia que muestra +3k con trade-through tiene una banda de 2.1k / +$0.4k te está diciendo algo real.
El experimento: bajando una estrategia maker por la escalera

Toma un maker deliberadamente simple — cotizaciones simétricas en el mejor bid/ask, clips fijos de 0.05 BTC, inventario limitado a ±0.5 BTC con aplanado taker en el límite. Un mes de datos de perpetuos BTCUSDT: velas de 1m para los peldaños bajos, diffs L2 de 100ms más el tape de trades para los peldaños altos; comisión maker de 1.0 bps, taker de 4.0 bps. El mismo código de señal en cada peldaño (núcleo compartido, de modo que la única variable es el modelo de fills). Los números a continuación son una corrida representativa nuestra — tus magnitudes diferirán según el exchange, el mes y el tamaño; la forma no:
| Peldaño | Modelo de fill | Tasa de fill de cotizaciones | Fills | PnL del mes | Veredicto |
|---|---|---|---|---|---|
| 0 | fill al cierre | 98% | 41,200 | +$14,800 | fantasía |
| 1 | apertura de siguiente vela / toque en velas de 1m | 89% | 37,400 | +$9,600 | fantasía con latencia |
| 2 | toque + spread y slippage fijo en aplanados taker | 89% | 37,400 | +$7,100 | costos modelados, fills aún ficticios |
| 3 | + recorrido de profundidad L2 en aplanados taker | 89% | 37,400 | +$6,400 | salidas honestas, entradas aún ficticias |
| 4a | trade-through (conservador) | 21% | 8,900 | -$3,900 | límite de estrés |
| 4b | agotamiento de cola, calibrado | 37% | 15,600 | -$700 | mejor estimación |
| 4c | agotamiento de cola, (optimista) | 44% | 18,700 | +$1,900 | borde superior |
| — | corrida shadow en vivo, mismo mes | 35% | 14,100 | -$1,150 | realidad |
Lee la tabla de arriba abajo y observa dónde muere la estrategia. No es en el peldaño 2 — las comisiones y el slippage recortan un 26% y la estrategia todavía luce robustamente rentable. Muere entre el peldaño 3 y el peldaño 4, y muere por una razón que ningún modelo de costos puede capturar: selección de fills. El fill por toque otorgó 37,400 fills, de los cuales la mayoría eran tocar-y-rebotar — pura captura de spread. El modelo consciente de la cola eliminó el 58% de esos fills, y los fills que eliminó fueron desproporcionadamente los rentables: cuando el nivel se toca ligeramente, la cola por delante de un maker que re-cotiza con latencia retail absorbe todo. Los fills que sobreviven hasta el peldaño 4 están sesgados hacia barridos que limpian el nivel — los fills donde el precio ya se está moviendo a través de ti. La tasa de fill cayó 2.4x; el PnL invirtió el signo. Esa asimetría — perder los buenos fills, conservar los malos — es selección adversa hecha mecánicamente explícita, y es invisible en todo peldaño por debajo del 4.
Nota también qué hizo la banda: [-1,900] abarca el cero con la estimación calibrada en -1,150. El simulador no clavó el PnL en vivo al dólar exacto — acertó el signo, la magnitud, y la tasa de fill dentro de 2 puntos. Para eso sirve un modelo de fills. El backtest del peldaño 1 erró el PnL en vivo por $10,750 en una estrategia cuyo edge bruto mensual total era de apenas unos pocos miles de dólares: el error del modelo de fills fue aproximadamente 3 veces el tamaño del alpha. De ahí la tesis: tu modelo de fills es una suposición más grande que tu alpha.
Una advertencia para los peldaños bajos: si tienes que vivir con datos de velas (peldaños 0-2), como mínimo resuelve la ambigüedad intravela con drill-down adaptativo de resolución — perforando de 1m a 1s/100ms/trades donde el SL, TP o los niveles de cotización caen dentro del rango de la vela. El drill-down corrige errores de secuenciación (qué nivel se tocó primero) pero no puede corregir errores de cola; es el complemento a nivel de resolución de datos de este artículo, no un sustituto del peldaño 4.
El bucle de calibración: cerrar contra fills en vivo
Un simulador de peldaño 4 tiene parámetros libres — , la latencia , la latencia de cancelación, la suposición de reposición de nivel. Sin calibrar, es solo una conjetura con otra forma. El bucle que lo convierte en un instrumento:
1. Registra todo en vivo. Cada evento de orden con timestamps del exchange: envío, ack, cada fill parcial, acks de amend, acks de cancelación. Más el estado L2 en el momento del envío. Esta es la misma disciplina de logging que exige la paridad backtest-live para su DivergenceMonitor — la calibración del modelo de fills es la capa más profunda de ese monitor.
2. Reproduce las mismas órdenes a través del simulador. Alimenta los datos de mercado registrados y las instrucciones de orden registradas (no los fills) al simulador. Ahora tienes resultados apareados: para cada orden en vivo, un destino simulado.
3. Compara distribuciones, no promedios, por segmentos. Una única coincidencia global de tasa de fill puede ocultar errores que se compensan entre sí (demasiado optimista en regímenes tranquilos, demasiado pesimista en ráfagas — neteando a "calibrado"). Segmenta por los factores determinantes:
import numpy as np
from scipy.stats import ks_2samp
def calibration_report(pairs, bucket_key):
"""pairs: [{'bucket':…, 'live_filled':bool, 'sim_filled':bool,
'live_ttf':float|None, 'sim_ttf':float|None}, …]"""
out = {}
for b in sorted({p['bucket'] for p in pairs}):
grp = [p for p in pairs if p['bucket'] == b]
live_fr = np.mean([p['live_filled'] for p in grp])
sim_fr = np.mean([p['sim_filled'] for p in grp])
live_ttf = [p['live_ttf'] for p in grp if p['live_ttf'] is not None]
sim_ttf = [p['sim_ttf'] for p in grp if p['sim_ttf'] is not None]
ks = ks_2samp(live_ttf, sim_ttf) if len(live_ttf) > 20 and len(sim_ttf) > 20 else None
out[b] = {
'n': len(grp),
'fill_rate_live': live_fr,
'fill_rate_sim': sim_fr,
'fill_rate_gap': sim_fr - live_fr, # signed: + means sim optimistic
'ttf_ks_pvalue': ks.pvalue if ks else None,
}
return out
Dos estadísticos por segmento: la brecha de tasa de fill con signo (simulador menos live) y una prueba KS sobre las distribuciones de tiempo-hasta-fill entre las órdenes llenadas. La comparación de tiempo-hasta-fill es la más reveladora — un simulador puede igualar las tasas de fill mientras llena en tiempos sistemáticamente equivocados, lo que corrompe cada estadística de inventario y selección adversa aguas abajo. Esta es precisamente la lección del enfoque de análisis de supervivencia de Lo-MacKinlay-Zhang: la ejecución es un problema de tiempo-hasta-evento, así que valídalo como tal.
4. Ajusta los parámetros, en orden de identificabilidad. Primero la latencia (medida directamente a partir de los timestamps de ack — no ajustada). Luego minimizando la brecha de tasa de fill a través de los segmentos de profundidad de cola. Luego revisa los segmentos de régimen de volatilidad: una brecha optimista persistente concentrada en los segmentos de ráfaga generalmente significa que tu simulador subestima los fills tóxicos por latencia de cancelación o la reposición de nivel, no .
5. Vuelve a correr la banda. Después de la calibración, la estimación de agotamiento de cola debería situarse dentro de la banda cerca del live, y — la verdadera prueba de aceptación — el ranking de las variantes de estrategia bajo el simulador debería coincidir con su ranking en modo shadow. Luego congela los parámetros y recalibra según un calendario; la dinámica de fills se desplaza con los niveles de comisión del exchange, los cambios de tick-size y la población de HFT, y un calibrado en marzo es una hipótesis para julio.
Expectativas de convergencia según nuestras corridas: un simulador de peldaño 4 sin calibrar típicamente cae dentro de ±10-15 puntos de la tasa de fill en vivo; tras una pasada de calibración, ±3-5 puntos, con los p-values de KS de tiempo-hasta-fill dejando de rechazar de forma uniforme. No harás mejor que eso con replay histórico — el residuo es la reacción del mercado hacia ti, que es el problema del peldaño 5.
Qué llevarse
- Nombra tu peldaño. Cada backtest se sitúa en esta escalera, elijas tú el peldaño o lo elija tu framework por ti. Si no puedes nombrar el peldaño de tu modelo de fills y sus sesgos conocidos, tu número de PnL tiene márgenes de error que no has visto.
- Los takers pueden detenerse en el peldaño 3. El recorrido de profundidad más la latencia medida tasan honestamente la ejecución agresiva a tamaño retail. Invierte el esfuerzo ahorrado en la calidad de los datos.
- Los makers empiezan en el peldaño 4. Por debajo de él, la lógica de fill de órdenes límite no es aproximada — selecciona un conjunto contrafactual de fills con sesgo de selección adversa opuesto. Los backtests con fill por toque de estrategias maker son el generador más fiable de estrategias que mueren al contacto con producción.
- Modela el ciclo de vida, no el fill. Fills parciales, amend que resetea la cola, latencia de cancelación — la máquina de estados es donde viven los fills tóxicos, y los fills tóxicos son donde muere el PnL de un maker.
- Reporta la banda. Los límites conservador y optimista cuestan dos corridas de backtest adicionales y convierten "mi backtest dice +3.9k, +$1.9k]" — que es una decisión distinta, y mejor.
- Calibra contra fills en vivo por segmentos. Un modelo de fills validado solo de forma agregada es un modelo de fills con errores compensatorios ocultos. Brechas de tasa de fill segmentadas más pruebas KS de tiempo-hasta-fill, recalibradas trimestralmente.
Los peldaños de la escalera no son gradaciones académicas — cada uno es una mentira específica que tu backtest deja de contarte. Sube hasta que las mentiras sean más pequeñas que tu edge.
Enlaces útiles
- Moallemi, C., Yuan, K. — A Model for Queue Position Valuation in a Limit Order Book (2016)
- Cont, R., Stoikov, S., Talreja, R. — A Stochastic Model for Order Book Dynamics, Operations Research 58(3), 549-563 (2010)
- Lo, A., MacKinlay, C., Zhang, J. — Econometric Models of Limit-Order Executions, Journal of Financial Economics 65(1), 31-71 (2002)
- Huang, W., Lehalle, C.-A., Rosenbaum, M. — Simulating and Analyzing Order Book Data: The Queue-Reactive Model, JASA 110(509), 107-122 (2015)
- Almgren, R., Chriss, N. — Optimal Execution of Portfolio Transactions (2001)
- Byrd, D., Hybinette, M., Balch, T. — ABIDES: Towards High-Fidelity Multi-Agent Market Simulation (2020)
- Binance API — Cancel-Replace order semantics
- CME Globex — Order modification and time priority rules
Cita
@article{soloviov2026fillsimulation,
author = {Soloviov, Eugen},
title = {Fill simulation: the ladder from close-price fantasy to queue-aware reality},
year = {2026},
url = {https://marketmaker.cc/blog/fill-simulation-partial-fills-backtest},
description = {Five rungs of fill simulation fidelity — from close-price fills to probabilistic queue-position models. Partial fills as a state machine, limit-fill probability bounds as a PnL bracket, and a calibration loop against live fills.}
}
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.