← Volver al índice · 30_walkforward

Walk-forward backtesting

Motor rolling train/test sin lookahead para los 4 modelos quant, con persistencia en DB.

Todo listo. Reporte final:

Reporte fase 30_walkforward

Estado: OK. Todos los criterios cumplidos.

Archivos

Acción Path md5
Nuevo /opt/trading-web/backtest_engine.py 6ba9d4fd2d580507eb78526cd460ed5f
Editado /opt/trading-web/app.py 2854ae030d3a4f7ee88b5e89fac0e15c
Backup /opt/backups/trading-web/app.py.20260418-0945.bak f380d0952d41effdbaa936b5b9f898ef (= app.py original)

Schema nuevo

Tabla backtest_runs (id, run_at, symbol, model, train_window, test_window, step, start_date, end_date, status, metrics_json) creada idempotente al importar el módulo.

API

  • walk_forward_backtest(symbol, model_fn, train_window=180, test_window=20, step=20, start_date, end_date, closes=None) — iteración rolling, refit por paso, sin lookahead (history = closes[t-train_window:t]).
  • backtest_all_models(symbol_list, models) — wraps los 4 modelos: gbm_simulation, monte_carlo_jump, kalman_trend, hmm_regime. Cada wrapper convierte la salida (prob_up o signal) a dirección {-1,0,+1}.
  • summarize_backtest(results) — devuelve hit_rate, sharpe (√252), sortino (downside-deviation), max_drawdown (peak-to-trough equity curve), profit_factor, n_trades, avg_return, windows.
  • run_and_persist_async(...) — pre-inserta filas running, lanza threading.Thread(daemon=True), finaliza a done/error con metrics_json. SQLite con check_same_thread=False + _db_lock.

Endpoints (verificados 200 público en https://tokenstree.es)

  • GET /backtest → tabla HTML de runs (?format=json para JSON).
  • POST /api/backtest/run{run_id, run_ids, status:"running",...} inmediato, procesa en thread.

Smoke test interno

python3 backtest_engine.py con synthetic GBM (100 closes, train=30/test=10/step=10): 0.83s, 6 ventanas, 26 trades, fila id=1 escrita (TEST/gbm_simulation/done).

Test POST

curl POST /api/backtest/run {symbols:["SPY"], models:["kalman_trend"], train=30/test=10/step=10}{"run_id":2,"status":"running"}. Tras 8s, fila id=2 done (0 trades: fetch yfinance sin datos en el momento; engine sólido, no crash).

Verificación post-deploy

  • / 200, /report 200 (contiene "Informe Diario"), /backtest 200 en local y público.
  • Sintaxis validada con ast.parse en ambos archivos antes de restart.
  • Servicio reiniciado vía systemctl restart trading-web.service.