---
title: "Estacionalidad Intradiaria IV - Busqueda de campo"
description: "Ampliamos el backtester como buscador de ventajas estacionales. Backtest de parametros para analizar estacionalidad intradiaria en futuros."
url: "https://pythonparatrading.com/estacionalidad-intradia-optimizacion/"
lang: "es"
date: "2025-04-14"
updated: "2026-08-29"
image: "https://pythonparatrading.com/content/images/2025/04/estacionalidad6.png"
tags: ["Estacionalidad", "Quant"]
series: "Estacionalidad en Python"
series_url: "https://pythonparatrading.com/series/estacionalidad-en-python/"
authors: ["Jesús Cuesta"]
---

# Estacionalidad Intradiaria IV - Busqueda de campo

> Búsqueda de campo: el backtester recorre todas las combinaciones de día, hora, minuto y velas, y guarda las métricas en un CSV.

- Idioma: es (español)
- Publicado: 2025-04-14
- Actualizado: 2026-08-29
- Temas: Estacionalidad, Quant
- Serie: Estacionalidad en Python (parte 4/4)
- Requisitos: Parte 03 (Estadísticas) · pandas · tqdm
- Dataset: Datos preprocesados de la Parte 01.
- Resumen: En esta entrega,ampliamos el backtester para utilizarlo como un buscador de amplio espectro y encontrar ventajas estacionales. Realizamos un backtest a todos los parametros necesarios para analizar la estacionalidad intradia del activo

Puntos clave:

- Método optimize con rangos de día, hora, minuto y velas en operación.
- Producto cartesiano de parámetros con itertools.product y progreso con tqdm.
- Métricas por combinación y valores a cero cuando no hay operaciones.
- Exportación de resultados a CSV como base para buscar ventajas estacionales.

---

En esta nueva entrega de la estacionalidad intradia, vamos a realizar una busqueda de campo. Consiste en realizar el backtest que hemos programado anteriormente en diferentes dias, diferentes horas y diferente intervalod entro de la operacion, para mapear el activo, y buscar las zonas donde podrian ocurrir las anomalias estadisticas, y tuvieran algun tipo de alpha.

Para poder seguir este articulo, es necesario haber leido los tres primeros articulos, que te dejo los enlaces aqui abajo

> **[Estacionalidad en Python. Buscando Patrones Intradia](https://pythonparatrading.com/estacionalidad-intradia-preprocesado/)**
> Tras un largo periodo totalmente desconectados, volvemos a escribir algunos apuntes para vosotros. En esta ocasion, vamos a programar desde cero, todo un proceso de research, y en lugar de ir a por un activo concreto, vamos a crear un metodo completo, que se reutilizable en el futuro, para poder

> **[Estacionalidad en Python II - Backtesting](https://pythonparatrading.com/estacionalidad-intradia-backtesting/)**
> Descubre cómo identificar patrones estacionales intradía en futuros y validar estrategias de trading mediante backtesting. Aprende a utilizar Python para analizar datos históricos, optimizar parámetros y evaluar el rendimiento de tus algoritmos antes de aplicarlos en el mercado real

> **[Estacionalidad en Python III - Estadisticas sobre la operativa](https://pythonparatrading.com/estacionalidad-intradia-estadisticas/)**
> En este articulo, analizamos el ratio de sharpe, el value at risk (VaR) el Conditional Value At Risk (CVaR), el System Quality Number (SQN) y otros ratios relevantes para analizar el backtest.

## Plan de Accion

Vamos a ampliar la funcionalidad de la clase, creando una funcion denominada optimize donde, a partir de un rango efectivo de parametros como

-   **Dias de la semana**
-   **Hora de Entrada**
-   **Minuto de Entrada**
-   **Velas Intrade**

Vamos a recorrer todo el espectro asignado, y almacenando los resultados en un dataframe, que posteriormente exportaremos a CSV, y sera la base para poder encontrar ventajas estadisticas dentro del activo.

Por simplificacion, no vamos a paralizar los procesos, se hara unicamente un unico proceso de forma concurrente. Pero el codigo puede acelerado sin demasiada complicacion, pero el objetivo de esta serie es el research, no la optimizacion operativa de los procesos.

## Programando la busqueda de campo

Vamos a crear una nueva funcion dentro de la clase, denominada optimize, que realizara la funcion de busqueda de alpha de forma estacional dentro del activo. Esta busqueda de campo corresponde en la realizacion de un backtest por cada uno de los parametros del rango introducido, y almacenar los resultados.

La clase deberia quedar tal que asi:

![Clase IntradaySeasonalBacktester plegada con el nuevo método optimize (rangos de día y hora) marcado en rojo](https://pythonparatrading.com/content/images/2025/04/image-22.png)

### Defininendo los parametros de la busqueda de campo

```python
    def optimize(self, weekday_range=range(0, 7), hour_range=range(0, 24), 
                minute_range=range(0, 60), bars_range=range(1, 11), 
                csv_path='optimization_results.csv'):
```

Los parametros que necesitaremos para lanzar la funcion son :

-   **Weekday range:** Un rango numerico de los dias que se quieren incluir dentro de la optimizacion. La optimizacion filtra por dias, considerando cada dia de la semana como un caso independiente.
-   **Hour range:** Rango horario que se ejecutara la busqueda, debe estar ajustado a los horarios y apertura y cierre del activo para evitar perder tiempo con optimizaciones donde el mercado no esta cotizando, y por consecuencia dara resultados 0 en todos los campos
-   **Minute range:** Este parametro es una lista fija de 0,15,30,45 por que nuestros datos estan resampleados en intervalos de 15 minutos. Pero si se trabaja con intervalos superiores o inferiores, deberia ser reajustado.
-   **Bars Range:** Hace referencia al rango de velas que estara el trade abierto. Se introducen en rango por que probara todos los valores del rango, haciendo la salida mas larga o mas corta, de uno en uno. Es la forma mas sencilla de manejar las salidas, y facilmente transformable a tiempo.

### Cargando las librerias necesarias

```python
        from itertools import product
        from tqdm import tqdm
        
        all_results = []
```

El primer paso es cargar las librerias necesarias. En este caso mediante ***tqdm*** vamos a crear un progressbar que nos muestre de forma visual el estado de la optimizacion, desde la funcion ***itertools.product*** vamos a crear todas las combinaciones posibles desde los parametros introducidos, para ir backtesteando uno a uno y guardando los resultados.

Del mismo modo, inializamos una lista denominada all\_results, donde vamos a ir guardando los parametros y ratios mas relevantes de la actualizacion.

```python
        total_combinations = len(weekday_range) * len(hour_range) * len(minute_range) * len(bars_range)
        
        print(f"Iniciando optimización con {total_combinations} combinaciones...")
        
```

Posterirmente vamos a calcular el numero toftal de combinatorias posibles, multiplicando la longitud del rango por cada uno de los parametros, y lo mostramos antes de empezar la busqueda de campo para que el usario tenga consciencia de la dificultad de la tarea.

```python
        parameter_combinations = product(weekday_range, hour_range, minute_range, bars_range)
        progress_bar = tqdm(parameter_combinations, total=total_combinations, 
                            desc="Optimizando", unit="combinación")
```

Posteriormente vamos a crear todas las combinanciones posibles entre los argumentos introducidos en el buscador de amplio espectro utilizando el product de itertools, definimos la progress bar, que acompanara al usuario mediante toda la optimizacion.

La función `product()` del módulo `itertools` en Python es una herramienta poderosa que genera el producto cartesiano de los iterables que le pasamos como argumentos. En términos simples, crea todas las combinaciones posibles de los elementos de las listas que le proporcionamos.

### Programando la busqueda de amplio espectro

```python
      for weekday, hour, minute, bars in progress_bar:
            backtester = IntradayBacktester(
                df=self.df.copy(),
                entry_weekday=weekday,
                entry_hour=hour,
                entry_minute=minute,
                bars_to_exit=bars)
            backtester.run_backtest()
            summary = backtester.get_summary()
```

La busqueda de amplio espectro, se trata de, para cada uno de los parametros de los rangos introducidos, los colocamos en una llamada al backtester IntradayBacktester, lo ejecutamos, y guardamos el sumary. Para posteriormente

```python

            result = {
                'entry_weekday': weekday if weekday is not None else 'All',
                'entry_hour': hour,
                'entry_minute': minute,
                'bars_to_exit': bars,
            }
            
            # Si hay trades, añadir todas las métricas
            if "message" not in summary:
                result.update(summary)  # Desempaquetar el diccionario summary
            else:
                # Si no hay trades, establecer valores predeterminados para todas las métricas
                for key in ['total_trades', 'winning_trades', 'losing_trades', 'win_rate',
                            'avg_profit', 'total_profit', 'max_profit', 'max_loss', 
                            'variance', 'profit_factor', 'sharpe', 'sqn', 'mdd',
                            'VaR', 'CVaR', 'beta', 'alpha']:
                    result[key] = 0
                result['total_trades'] = 0
            
            # Añadir el resultado a la lista
            all_results.append(result)
```

**Crea un diccionario 'result' con los parámetros básicos de entrada** (día de la semana, hora, minuto y número de barras para salir) y luego lo enriquece con métricas de rendimiento si se han realizado operaciones.

**Si no hay operaciones, establece valores predeterminados de cero para todas las métricas importante**s como número total de operaciones, tasa de éxito, beneficio promedio, factor de beneficio, ratio de Sharpe, entre otros.

Finalmente, este resultado completo se añade a una lista 'all\_results', que presumiblemente se utilizará para análisis posteriores o para generar informes sobre el rendimiento de la estrategia en diferentes escenarios temporales.

Ademas mediante el siguiente codigo, si se han producido resultados, se actualiza la barra de progreso, para proporcionar feedback al usuario de lo que esta ocurriendo por detras

```python
if result['total_trades'] > 0:
                progress_bar.set_postfix(trades=result['total_trades'], win_rate=f"{result['win_rate']:.2f}")
```

### Para Finalizar

Una vez backtesteadas todas las posibilidades posibles, guardamos los resultados en un dataframe, exportamos el CSV y mostramos un print en pantalla, anunciando que hemos acabado la busqueda. De esta forma unicamente se escriben los resultados una vez acabados. Para optimizaciones extremadamente largas, o donde la probabilidad de error es mayor, deberia actualizarse el csv, cada N optimizaciones realizadas con exito incluso cada una, pero para nuestra labor, es mas que suficiente.

```python
        # Crear DataFrame con todos los resultados
        results_df = pd.DataFrame(all_results)
        
        # Guardar el DataFrame completo en CSV al final
        results_df.to_csv(csv_path, index=False)
        
        print(f"Optimización completada. Resultados guardados en {csv_path}")
        return results_df
```

## Pseudocodigo

Por si alguien no ha entendido muy bien lo que se pretende, o quiere hacerlo a su manera, le proporciono tambien el pseudocodigo de la funcion completa

```
función optimize(weekday_range, hour_range, minute_range, bars_range, csv_path):
    inicializar lista all_results
    calcular total_combinations
    crear parameter_combinations usando product()
    crear barra de progreso

    para cada combinación de (weekday, hour, minute, bars) en parameter_combinations:
        crear nueva instancia de IntradayBacktester con parámetros actuales
        ejecutar backtest
        obtener resumen estadístico
        crear diccionario result con parámetros básicos
        
        si hay trades:
            añadir todas las métricas al diccionario result
        si no:
            establecer valores predeterminados para todas las métricas
        
        añadir result a all_results
        actualizar barra de progreso

    crear DataFrame results_df con all_results
    guardar results_df en CSV
    devolver results_df
```

### Ejecutando desde el Notebook

![Celda que lanza model.optimize sobre el ES con 120 combinaciones y su barra de progreso al 35 %](https://pythonparatrading.com/content/images/2025/04/image-23.png)

Para ejecutar desde un notebook o como cualquier script, unicamente se necesita seguir la siguiente metodologia

-   Cargar las librerias necesarias, en este caso pandas y el IntradayBacktester
-   Cargar el dataframe preprocesado a utilizar
-   Lanzar el model.optimize con los rangos ajustados. En este caso buscara de lunes a miercoles, de 5 a 10 en los minutos 15,30,45 y 00 y una ventana de salida de 1 a 3 barras.

![Optimización completada: tabla de 120 combinaciones de día, hora, minuto y barras con trades, MDD y win rate](https://pythonparatrading.com/content/images/2025/04/image-24.png)

Una vez ejecutada la actualizacion, nos devolvera el dataframe final, que podria ser asignado a una variable mediante

```python
resultados = model.optimize(parametros)
```

Pero lo a guardado en un .csv, que posteriormente cargaremos. En este caso el archivo csv que corresponde a los resultados de la optimizacion los encontramos es LE\_optimization\_results.csv

Si quieres repasar la entrega anterior, no te pierdas [el tercer artículo de la serie](https://pythonparatrading.com/estacionalidad-intradia-estadisticas/), donde se detallan las estadísticas de la operativa.

Si quieres repasar la entrega anterior, no te pierdas [el tercer artículo de la serie](https://pythonparatrading.com/estacionalidad-intradia-estadisticas/), donde se detallan las estadísticas de la operativa.

## Conclusiones

En este nuevo articulo, hemos visto como llegar hasta poder buscar ventajas estacionales en todo el espectro del activo. En el proximo y ultimo articulo, veremos como interpretar los datos de la optimizacion de una forma sencilla, mediante diferentes plots, diferentes estadisticos, etc..

Nos vemos en la proxima entrega, ante cualquier pregunta, no dudes en contactarme en jcx\[a\]quantarmy.com

Un saludo, y hasta la proxima!
