Eugen Soloviov
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.
Articles
El negativo honesto: decenas de miles de backtests, cinco majors, ninguna ventaja robusta
El cierre del arco de búsqueda y sobreajuste, y termina en un resultado negativo — el correcto. Una búsqueda de doble timeframe sobre un solo símbolo (ETHUSDT) encontró una configuración con +16.35% fuera de muestra y +2.62% en un holdout intacto; el ratio de Sharpe deflactado, contando ~37,000 pruebas, lo deflactó a 0.00. Una pasada entre instrumentos sobre cinco majors (ETH/BTC/SOL/BNB/XRP, ~1.18M de barras de 1m cada uno), seleccionando por la mediana fuera de muestra, lo remata definitivamente: doble DSR 0.24 / PBO 0.264, triple DSR 0.14 / PBO 0.327 — ambos fallan los filtros. El campeón es rentable en 1 de 5 símbolos y negativo en el resto. Para esto existe el aparato anti-sobreajuste: para impedir que despliegues el mejor del ruido como alfa.
Demostrando la ausencia de look-ahead en backtests multi-timeframe: perturbar el futuro para probar que el pasado no puede verlo
Los backtests multi-timeframe filtran el futuro a través de una vela de temporalidad superior en formación, cuyo cierre final aún no existe. No se puede llegar a la confianza mediante revisión de código — hay que probarlo. Reproducimos exactamente la regla de vela cerrada del bot en vivo, y luego demostramos que no hay filtración con una sonda de futuro desplazado: perturbamos cada vela futura y verificamos que cada señal y operación pasada permanece idéntica bit a bit. 25/25 comprobaciones de paridad superadas, y la sonda tiene mordiente.
Cuándo Compensa la GPU: El Roofline del Sweep de Parámetros, Donde un Titular de 167x Es en Realidad 27x de Algoritmo por 6.2x de Hardware
La ventaja de la GPU sobre la CPU crece con el tamaño del batch — de 54.5x con un combo por llamada hasta 359.6x con 61 en nuestro precómputo de indicadores multi-timeframe — porque un sweep pequeño no puede amortizar el overhead de lanzamiento de kernels y de transferencia. Descomponemos un titular de 167x en una victoria algorítmica de 27x que también ayuda a la CPU y una victoria de hardware de 6.2x, mostramos que la ventaja real de la GPU frente a la mejor CPU es solo 3.2x en single-timeframe y 6.2x en multi, y damos una guía de decisión sobre cuán ancho debe ser un sweep antes de que valga la pena apostar por una GPU.
La trampa de precisión de la GPU: cómo un backtest en fp32 sobre Apple Metal devuelve basura en silencio
La GPU Metal de Apple no tiene float64. Porta un backtest vectorizado a ella de forma ingenua y la tentadora WMA por suma de prefijos desborda fp32 —error relativo máximo de 211×— y aun así se ejecuta y devuelve números de aspecto plausible. La solución no es más precisión; es una formulación distinta: una convolución directa por ventanas, segura en fp32 hasta 8×10⁻⁷ y 55.9× más rápida que numba de un solo hilo. La trampa, la aritmética y cómo demostrar que no caíste en ella.
La Puerta de Fidelidad: el Backtesting de Grueso a Fino te Engaña Más Rápido, a Menos que el Proxy Barato Clasifique Igual que el Costoso
La búsqueda de profundización progresiva / multi-fidelidad (ASHA, eliminación sucesiva, Hyperband) filtra miles de configuraciones de forma barata y solo asciende a los supervivientes a la evaluación completa y costosa. Es una aceleración genuina, pero colapsa en silencio si la clasificación de baja fidelidad no coincide con la de alta fidelidad. Medimos la correlación de rango entre pliegues: en un solo pliegue, la ρ de Spearman puede ser 0.03 (clasifica casi al azar), subiendo a 0.43, 0.67, 0.78, 0.91 a medida que se acumulan los pliegues. La solución es una puerta obligatoria: medir primero ρ(barato, completo) y elevar automáticamente la fidelidad mínima hasta el primer escalón donde ρ ≥ 0.5.
Búsqueda aleatoria vs. inteligente: el cruce es el costo de evaluación, no el algoritmo
Cuando un backtest es barato, un Sobol scrambled y tonto gana en throughput puro — los samplers inteligentes (TPE, CMA-ES, ASHA) pagan un impuesto de ask/tell en Python que los frena 20 veces, por lo que evalúan muchos menos puntos al mismo wall-clock y pierden. Haz que cada evaluación sea costosa (multi-TF + folds de walk-forward) y el cruce se invierte. Medimos ambos regímenes, y por qué la fidelidad de rank por fold (ρ@1 subiendo 0.03→0.43) es la condición previa para que el pruning valga la pena.
El espacio de parámetros de dos ejes: por qué la mayor parte de tu barrido debería ser casi gratis
No todos los parámetros cuestan lo mismo al buscar. Los parámetros de una estrategia se dividen en un eje costoso (indicadores, recalculados sobre toda la serie) y un eje barato (umbrales de decisión, un recorrido O(n) sobre señales precalculadas). Como los indicadores son invariantes a los umbrales, los calculas una vez y barres miles de configuraciones de umbrales a ~5.600 cfg/s, aproximadamente 1.600 veces más barato que recalcular por configuración. Una re-tasación de la maldición de la dimensionalidad.
El impuesto del framework: cuando tu librería de backtest es más lenta que un bucle ingenuo de pandas
Comparamos ocho motores de backtest en un mismo barrido de parámetros idéntico: 150k barras, 80 combinaciones de cruce de HMA, con la paridad de número de operaciones fijada en 2707. Dos de los frameworks orientados a eventos más populares resultaron más lentos que un bucle de pandas escrito a mano, mientras que un motor vectorizado/compilado ejecutó el mismo trabajo unas 13,000× más rápido. Un estudio de la sobrecarga por barra que las librerías populares nunca fueron diseñadas para amortizar.
The Probability of Backtest Overfitting: Did Your Search Beat a Coin Flip?
The Deflated Sharpe Ratio prices the winning strategy; PBO prices the search that picked it. Combinatorially Symmetric Cross-Validation runs C(16,8) = 12,870 train/test splits over a 1000x200 performance matrix and asks: does the in-sample winner land in the bottom half out of sample? The catch almost everyone misses — PBO's null is 0.5, not 1. On 200 zero-edge strategies the best in-sample annualized Sharpe of 1.98 collapses to 0.06 out of sample and PBO = 0.476: a coin flip, fully overfit. Plant a real edge (annualized Sharpe 2.38) and PBO drops to 0.001, the in-sample 3.73 surviving to an out-of-sample 2.34. A moving-average grid on a pure random walk has no out-of-sample skill either — PBO 0.463 averaged over 60 matrices, statistically indistinguishable from the null — and on one representative matrix the mirage is vivid: a best in-sample Sharpe of 2.33 collapses to a median out-of-sample -0.22, PBO 0.573, a 63% chance of a loss.
The IPC Tax: Put the Backtest Engine Behind a Socket and Lose 13% — Almost None of It to the Socket
We ported a numba backtest kernel line-for-line to Rust and called it across a process boundary four ways, with an equivalence gate confirming identical PnL to the last trade. Shipping the entire 1.2 MB price series through a Unix socket costs ~2 ms — about 0.1% of the job. JSON-encoding the same payload costs 1348x more than raw bytes, chatty per-combo calls re-ship the data 80 times, and a per-bar call pattern would pay 2.1 s of pure IPC on a 2.0 s job. The boundary is cheap; the tax is in how you cross it.
The Deflated Sharpe Ratio: How Many of Your Backtest 'Winners' Survive Multiple Testing?
A parameter search is a machine for manufacturing luck. On pure noise — 1,000 strategies with zero true edge — the best annual Sharpe averages 1.63 and the naive significance test flags a discovery 100% of the time. We build controlled ground truth and show that the Deflated Sharpe Ratio, the Harvey-Liu haircut, and White's Reality Check restore honesty: false discoveries drop from 1.000 to 0.001-0.057, genuine edges above the noise ceiling are kept with power ~1 — and one real trap (correlated grids) where the raw DSR over-deflates and the verdict must be read across a whole band of effective-trial estimates, not one.
Objective-Function Design: The Metric You Optimize Secretly Picks Your Strategy
To search for the 'best' strategy you must first define 'best' — and that scalar silently chooses the winner. On synthetic data with a known edge (600 seeds, T=2000, 80 thresholds), a naive per-trade Sharpe crowns a lottery: it picks a sub-5%-exposure winner in 56% of seeds and degenerates in 57% — on the starkest seed, 8 trades posting an in-sample Sharpe of 21.09 that collapses to 0.13 out of sample. The honest repair is almost dull: measure on the full timeline, which never degenerates (out-of-sample 1.71). A trade-count (conf_k) shrinkage and an exposure floor can retrofit a per-trade metric, but even fully repaired they only match full-timeline Sharpe (1.70 vs 1.71) — never beat it. Goodhart's law, in a backtest, with controlled ground truth.