Saltar al contenido

Lección 16 de 20 · Lectura y práctica

Diseñar arquitectura del bot con módulos separados

Concepto claveLa arquitectura modular en bots de trading es similar a un equipo de especialistas en una sala de operaciones financiera. En lugar de tener una sola persona haciendo todo (desde analizar datos hasta ejecutar.

Del concepto a la práctica

Taller de esta lección

La modularidad se comprueba por las dependencias, no por la cantidad de archivos. Un flujo claro puede tener DataFetcher, Strategy, RiskManager, ExecutionSimulator y Logger; cada componente recibe datos por argumentos y devuelve resultados explícitos. La estrategia no debe leer credenciales ni modificar el saldo.

Ejemplo resuelto

Strategy recibe una fila con medias y devuelve buy, sell o hold. RiskManager recibe señal, saldo y stop, y devuelve cantidad o rechazo. ExecutionSimulator aplica el precio y la comisión. Así, una prueba de estrategia puede ejecutarse con datos fijos y sin conexión.

Pruébalo

  1. Dibuja entradas y salidas de cada módulo.

  2. Define una estructura de señal inmutable.

  3. Sustituye la ejecución externa por un simulador local.

  4. Registra una razón para cada rechazo.

Comprueba tu resultado

Error frecuente: usar una variable global de posición desde todos los módulos. Corrección: pasa estado explícito y devuelve cambios controlados.

Ejercicio: envía una señal buy con saldo 1.000 y riesgo rechazado. Resultado esperado: el simulador no altera saldo ni posición y el logger conserva la razón del rechazo.

Prueba cronológica de una estrategia con datos históricos, costes y riesgo antes de validarla en otro periodo.
CursaloMapa de práctica
Probar una estrategia sin dinero real

Una simulación utiliza datos históricos y debe incluir comisiones y deslizamiento. Separar el periodo de desarrollo del de validación reduce el ajuste al pasado. Examina pérdidas y caídas además del resultado; una prueba histórica no garantiza ganancias futuras.

Ver la infografía en tamaño completo ↗

Concepto clave

La arquitectura modular en bots de trading es similar a un equipo de especialistas en una sala de operaciones financiera. En lugar de tener una sola persona haciendo todo (desde analizar datos hasta ejecutar órdenes), divides las responsabilidades en módulos especializados que trabajan juntos. Cada módulo tiene una función específica y se comunica con los demás a través de interfaces claras.

Esta separación permite mantenibilidad (puedes actualizar un módulo sin afectar los demás), escalabilidad (puedes añadir nuevas estrategias o APIs fácilmente) y testabilidad (puedes probar cada componente por separado). Imagina un coche: el motor, la transmisión y los frenos son módulos separados que funcionan juntos; si falla uno, no tienes que desmontar todo el vehículo.

Cómo funciona en la práctica

Vamos a diseñar un bot con cinco módulos principales que se comunican en un flujo secuencial:

  1. DataFetcher: Obtiene datos de mercado de Binance API (ej., precios, volumen).
  2. Strategy: Analiza los datos y genera señales de compra/venta basadas en reglas predefinidas.
  3. RiskManager: Evalúa el riesgo de cada señal (ej., límites de posición, stop-loss).
  4. OrderExecutor: Envía órdenes a Binance si la señal pasa el filtro de riesgo.
  5. Logger: Registra todas las acciones y resultados para análisis posterior.

Estos módulos se organizan en un bucle principal que se ejecuta periódicamente (ej., cada minuto). La clave es que cada módulo solo conoce su propia tarea y se comunica a través de objetos de datos simples (como diccionarios o clases).

Código en acción

Aquí tienes un ejemplo básico de la estructura modular en Python. Primero, el antes: un script monolítico que hace todo en una sola función:

# Antes: Código monolítico difícil de mantener
def run_bot():
    # Obtener datos
    data = fetch_from_binance('BTCUSDT', '1m')
    # Analizar estrategia
    signal = simple_moving_average_strategy(data)
    # Gestionar riesgo
    if check_risk(signal):
        # Ejecutar orden
        execute_order(signal)
    # Loggear
    log_to_file(signal)

Ahora, el después: refactorizado en módulos separados:

# Después: Arquitectura modular clara
class DataFetcher:
    def fetch(self, symbol, interval):
        from binance.client import Client
        client = Client(api_key, api_secret)
        klines = client.get_klines(symbol=symbol, interval=interval)
        return [{"close": float(k[4])} for k in klines]

class Strategy:
    def analyze(self, data):
        closes = [d["close"] for d in data]
        sma = sum(closes[-20:]) / 20
        current_price = closes[-1]
        return "BUY" if current_price > sma else "SELL"

class RiskManager:
    def validate(self, signal, current_positions):
        max_position = 0.1  # Máximo 10% del capital
        return len(current_positions) < max_position

class OrderExecutor:
    def execute(self, signal, symbol, quantity):
        from binance.client import Client
        client = Client(api_key, api_secret)
        if signal == "BUY":
            order = client.order_market_buy(symbol=symbol, quantity=quantity)
        else:
            order = client.order_market_sell(symbol=symbol, quantity=quantity)
        return order

class Logger:
    def log(self, event):
        with open('bot_log.txt', 'a') as f:
            f.write(f"{event}\n")

# Bucle principal que integra los módulos
def main():
    fetcher = DataFetcher()
    strategy = Strategy()
    risk = RiskManager()
    executor = OrderExecutor()
    logger = Logger()
    
    while True:
        data = fetcher.fetch('BTCUSDT', '1m')
        signal = strategy.analyze(data)
        if risk.validate(signal, []):
            order = executor.execute(signal, 'BTCUSDT', 0.001)
            logger.log(f"Orden ejecutada: {order}")
        time.sleep(60)

Errores comunes

  • Acoplamiento fuerte entre módulos: Evita que un módulo dependa de detalles internos de otro. Usa interfaces abstractas o clases base.
  • Falta de manejo de errores: Cada módulo debe gestionar sus propias excepciones (ej., fallos de API en DataFetcher) y propagar errores claros.
  • Comunicación excesiva: No pases datos innecesarios entre módulos; solo lo esencial para reducir complejidad.
  • Ignorar la concurrencia: En bots avanzados, múltiples módulos pueden ejecutarse en paralelo; usa threading o asyncio con cuidado.
  • Olvidar el logging: Sin un Logger robusto, será imposible depurar o auditar el bot en producción.

Checklist de dominio

  1. ¿Puedes añadir una nueva estrategia sin modificar el módulo OrderExecutor?
  2. ¿Cada módulo tiene una responsabilidad única y clara?
  3. ¿La comunicación entre módulos usa estructuras de datos simples (ej., dicts, dataclasses)?
  4. ¿Hay manejo de errores específico en cada módulo?
  5. ¿El bot puede escalar para manejar múltiples símbolos o intervalos?
  6. ¿El logging captura suficientes detalles para análisis post-ejecución?
  7. ¿Los módulos son testables de forma aislada (ej., con datos mock)?

Refactorizar un bot monolítico en arquitectura modular

En este ejercicio, tomarás un script de bot de trading existente (monolítico) y lo refactorizarás en una arquitectura modular. Sigue estos pasos:

  1. Descarga el script inicial desde https://ejemplo.com/bot_monolitico.py (simula un bot que obtiene datos, aplica una estrategia RSI, y ejecuta órdenes en una sola función).
  2. Analiza el código y identifica las responsabilidades que pueden separarse en módulos (ej., DataFetcher, Strategy, RiskManager, OrderExecutor, Logger).
  3. Crea un nuevo archivo bot_modular.py y define clases para cada módulo, basándote en el ejemplo de la lección.
  4. Implementa la lógica de cada módulo, asegurándote de que solo expongan métodos públicos necesarios (ej., fetch(), analyze()).
  5. Diseña un bucle principal que instancie los módulos y los coordine en secuencia (obtener datos → analizar → gestionar riesgo → ejecutar → loggear).
  6. Prueba tu bot modular con datos mock (usa una lista de precios falsos) para verificar que los módulos funcionan juntos sin errores.
  7. Documenta los cambios en un README breve, explicando las ventajas de la nueva arquitectura.
Pistas
  • Comienza por extraer la lógica de obtención de datos en una clase DataFetcher; usa la biblioteca requests o binance-python si es necesario.
  • Asegúrate de que los módulos se comuniquen a través de parámetros y return values, no variables globales.
  • Para probar sin conexión a Binance, mockea la API en DataFetcher devolviendo datos estáticos.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con Desarrollo de Bots de Trading Algorítmico con Python y Binance API

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.