Comparación de Backtrader y Zipline en estrategias compatibles
Resumen
Esta auditoría compara Backtrader y Zipline con ML4T en casos reales de estrategia, usando solo combinaciones de activos y contratos que cada motor y el paquete de datos congelado pueden representar de forma nativa. Incluye asignación de ETF y un panel de acciones US para ambos motores, además de futuros CME y asignación de FX cotizadas en USD para Backtrader. Se excluye la financiación de perpetuos de criptomonedas porque ninguno de los motores ofrece la compatibilidad nativa necesaria. La auditoría informa de concordancia en las ejecuciones, marcas temporales de valoración y comparaciones del valor de la cuenta, y afirma que las seis filas requeridas pasan las comprobaciones.
El tiempo de ejecución se mide solo para la ejecución del motor en las filas que superan las comprobaciones de corrección; la preparación de datos y el trabajo del adaptador quedan fuera del intervalo medido. Las proporciones comunicadas no deben generalizarse a otras estrategias o máquinas. Las pruebas de estrés sintéticas aportan evidencia secundaria de conformidad por pares: ambos perfiles de motor superan las pruebas frente a sus perfiles correspondientes de ML4T, mientras que los distintos valores finales reflejan convenciones distintas de cada framework. Estas pruebas de estrés evalúan la escala y la gestión de eventos, no la compatibilidad de estrategias con datos reales.
Ideas clave
- Compara frameworks solo en estrategias y modelos de activos que ambos puedan representar de forma nativa.
- La auditoría comprueba por separado la precisión de las ejecuciones, los valores de cuenta y las marcas temporales de valoración.
- Las filas de activos no compatibles se excluyen del denominador utilizado para calcular la tasa de aprobación.
- La medición exclusiva del motor excluye la preparación de datos y adaptadores; no debe generalizarse entre máquinas o estrategias.
- Las pruebas de estrés sintéticas aportan evidencia de conformidad por pares, mientras que las filas con datos reales determinan las comparaciones de estrategias.
Etiquetas
Texto completo
# Backtrader and Zipline on Current Case-Study Strategies
# Backtrader and Zipline on Current Case-Study Strategies
This notebook reports the Backtrader and Zipline Reloaded rows from the current real-strategy
audit. It does not infer asset support from ML4T's configurability: a pair is included only when
the external engine and frozen bundle can express the same native contract.
**Learning objectives**
- Compare Backtrader and Zipline against ML4T on supported real strategies
- Apply a monetary comparison unit to account values without weakening fill comparison
- Interpret the measured engine-only runtime boundary
- Use synthetic stress evidence as a secondary conformance result
**Book reference**: Chapter 16, Section 16.3
## Setup
```python
"""Current Backtrader and Zipline parity evidence."""
import json
import polars as pl
from IPython.display import display
from utils.paths import get_chapter_dir
```
```python
# Production defaults - Papermill injects overrides after this cell
ROUND_SECONDS = 3
```
```python
AUDIT_PATH = get_chapter_dir(16) / "resources" / "framework_parity_audit.json"
audit = json.loads(AUDIT_PATH.read_text(encoding="utf-8"))
FRAMEWORKS = ["backtrader", "zipline"]
FRAMEWORK_NAMES = {
key: f"{audit['frameworks'][key]['display_name']} {audit['frameworks'][key]['version']}"
for key in FRAMEWORKS
}
CASE_NAMES = {
"etfs": "ETF allocation",
"cme_futures": "CME futures",
"crypto_perps_funding": "Crypto perpetual funding",
"fx_pairs": "FX allocation (USD-quoted pairs)",
"us_equities_panel": "US equity panel",
}
```
## 1. Required comparisons
```python
results = (
pl.DataFrame(audit["real_strategy_records"])
.filter(pl.col("framework").is_in(FRAMEWORKS))
.with_columns(
pl.col("case_study").replace_strict(CASE_NAMES).alias("strategy"),
pl.col("framework").replace_strict(FRAMEWORK_NAMES).alias("engine"),
)
.select(
"strategy",
"engine",
"status",
"fills",
"valuations",
"valuation_timestamps_match",
"equity_gap",
"equity_raw_gap",
"terminal_gap",
"terminal_raw_gap",
)
.sort("strategy", "engine")
)
assert results.height == 6
assert results.filter(pl.col("status") == "pass").height == 6
assert results["valuation_timestamps_match"].all()
display(results)
```
Backtrader and Zipline both participate in the ETF and US equity-panel comparisons. Backtrader
also participates in the CME and USD-quoted foreign-exchange comparisons. The fill stream is
compared at eight-decimal price precision and five-decimal quantity precision, while account
values must round to the same cent. Zipline has no required CME or spot-FX row because the frozen
inputs do not map to its native asset models.
## 2. Unsupported asset models
```python
unsupported = (
pl.DataFrame(audit["unsupported_records"])
.filter(pl.col("framework").is_in(FRAMEWORKS))
.with_columns(
pl.col("case_study").replace_strict(CASE_NAMES).alias("strategy"),
pl.col("framework").replace_strict(FRAMEWORK_NAMES).alias("engine"),
)
.select("strategy", "engine", "reason")
.sort("strategy", "engine")
)
display(unsupported)
```
Neither engine is credited with crypto-perpetual funding support it does not natively provide.
Unsupported rows are excluded from the pass denominator.
## 3. Engine-only timing
Timing is retained only for correctness-passing rows and covers the engine call only.
```python
timing = (
pl.DataFrame(audit["performance_records"])
.filter(pl.col("framework").is_in(FRAMEWORKS))
.with_columns(
pl.col("case_study").replace_strict(CASE_NAMES).alias("strategy"),
pl.col("framework").replace_strict(FRAMEWORK_NAMES).alias("engine"),
pl.col("framework_median_seconds").round(ROUND_SECONDS).alias("external_seconds"),
pl.col("ml4t_median_seconds").round(ROUND_SECONDS).alias("ml4t_seconds"),
pl.col("framework_to_ml4t_ratio").round(2).alias("external_div_ml4t"),
)
.select("strategy", "engine", "external_seconds", "ml4t_seconds", "external_div_ml4t")
)
assert timing.height == 6
display(timing)
```
The timer excludes data and adapter preparation. The ratios should not be applied to other
strategies or machines.
## 4. Synthetic stress evidence
```python
stress = (
pl.DataFrame(audit["synthetic_stress"]["records"])
.filter(pl.col("framework").is_in(FRAMEWORKS))
.with_columns(pl.col("framework").replace_strict(FRAMEWORK_NAMES).alias("engine"))
.select("engine", "intents", "fills", "trades", "terminal_value", "status")
)
display(stress)
```
Both synthetic stress rows pass against their matching ML4T profiles. Their terminal values differ
because the profiles reproduce different framework conventions. The test is pairwise: ML4T versus
Backtrader and ML4T versus Zipline. The workload tests scale and event conventions, while the
required rows above determine the real-data comparison.Se muestra íntegramente con atribución según la licencia de la fuente. Licencia: MIT
Este resumen lo redactó el agente de investigación de Stratmill a partir del original; no es una copia de la fuente.