En un mundo donde los datos se mueven a la velocidad de la luz y los traders duermen con una mano en el celular, tener un bot de señales de futuros ya no es una novedad. Pero tener un panel de control web para tu bot… eso ya es otro nivel.

Si ya construiste tu bot con Python, Binance y Telegram siguiendo la guía de este blog (el cual puedes acceder en este enlace), ahora es momento de evolucionar. Porque no se trata solo de recibir mensajes: se trata de ver todo el ecosistema en tiempo real, modificar parámetros desde el navegador, consultar el historial de señales, pausar o reanudar el bot, y soñar con una futura app móvil.

Y todo eso lo vamos a lograr con Flask, un microframework que es pequeño en peso, pero gigante en posibilidades.

Este artículo es tu hoja de ruta hacia un Dashboard cripto modular, escalable y visualmente claro, listo para convertirse en el centro de mando de tu estrategia de trading automatizado.

Prepárate. Esto va más allá del código. Es arquitectura, UX, seguridad y visión de futuro.


1. Objetivos del Panel Web

Antes de escribir una sola línea de código, aclaremos para qué vamos a construir este dashboard:

  • Visualizar en tiempo real las últimas señales generadas
  • Mostrar el estado de los pares configurados, intervalos y valores de indicadores
  • Permitir modificar configuraciones del bot desde el navegador
  • Ver el histórico de señales (consultas por fecha, par, tipo de señal)
  • Pausar/reanudar el bot de forma manual

2. Estructura del Proyecto (ampliada)

Vamos a ampliar nuestro proyecto anterior de esta forma:

bot_senales_binance/
├── config/
│   └── settings.json
├── core/
│   ├── binance_api.py
│   ├── indicators.py
│   ├── signal_engine.py
├── telegram/
│   └── notifier.py
├── web/
│   ├── app.py
│   ├── routes.py
│   ├── forms.py
│   ├── utils.py
│   └── templates/
│       ├── base.html
│       ├── dashboard.html
│       ├── settings.html
│       └── logs.html
├── static/
│   └── style.css
├── data/
│   └── logs.db
├── main.py
├── requirements.txt
└── .env

3. Instalación de Dependencias Web

pip install flask flask-wtf flask-sqlalchemy flask-bootstrap

Agrega al requirements.txt:

flask
flask-wtf
flask-sqlalchemy
flask-bootstrap

4. Iniciar la App Flask

Archivo: web/app.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv("SECRET_KEY", "123456")
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../data/logs.db'
db = SQLAlchemy(app)
Bootstrap(app)

from web import routes

Archivo: web/routes.py

from flask import render_template, request, redirect, url_for
from web.app import app, db
from web.forms import SettingsForm
from web.utils import load_settings, save_settings

@app.route("/")
def dashboard():
    signals = []  # Lógica para cargar últimas señales desde la DB o archivo
    return render_template("dashboard.html", signals=signals)

@app.route("/settings", methods=["GET", "POST"])
def settings():
    form = SettingsForm()
    current_settings = load_settings()

    if request.method == "GET":
        form.symbols.data = ",".join(current_settings["symbols"])

    if form.validate_on_submit():
        symbols = form.symbols.data.split(",")
        new_config = {
            "symbols": symbols,
            "interval": form.interval.data,
            "indicators": {
                "rsi": int(form.rsi.data),
            },
            "signal_thresholds": {
                "rsi_overbought": int(form.overbought.data),
                "rsi_oversold": int(form.oversold.data),
            }
        }
        save_settings(new_config)
        return redirect(url_for("dashboard"))

    return render_template("settings.html", form=form)

Archivo: web/forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, SubmitField
from wtforms.validators import DataRequired

class SettingsForm(FlaskForm):
    symbols = StringField("Símbolos (separados por coma)", validators=[DataRequired()])
    interval = StringField("Intervalo (ej: 15m)", validators=[DataRequired()])
    rsi = IntegerField("RSI window", validators=[DataRequired()])
    overbought = IntegerField("RSI Overbought", validators=[DataRequired()])
    oversold = IntegerField("RSI Oversold", validators=[DataRequired()])
    submit = SubmitField("Guardar Cambios")

5. Templates (HTML con Bootstrap)

templates/base.html

<!doctype html>
<html lang="es">
  <head>
    <title>Panel del Bot</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
  </head>
  <body>
    <div class="container mt-4">
      {% block content %}{% endblock %}
    </div>
  </body>
</html>

templates/dashboard.html

{% extends "base.html" %}
{% block content %}
<h2>Señales Recientes</h2>
<table class="table">
  <thead><tr><th>Par</th><th>Tipo</th><th>RSI</th><th>Fecha</th></tr></thead>
  <tbody>
    {% for s in signals %}
      <tr>
        <td>{{ s.symbol }}</td>
        <td>{{ s.type }}</td>
        <td>{{ s.rsi }}</td>
        <td>{{ s.date }}</td>
      </tr>
    {% endfor %}
  </tbody>
</table>
<a href="{{ url_for('settings') }}" class="btn btn-primary">Configurar Bot</a>
{% endblock %}

6. Leer y Guardar Config desde la Web

web/utils.py

import json

def load_settings():
    with open("config/settings.json") as f:
        return json.load(f)

def save_settings(data):
    with open("config/settings.json", "w") as f:
        json.dump(data, f, indent=2)

7. Registrar Historial en SQLite

Modelo en web/app.py

class SignalLog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    symbol = db.Column(db.String(10))
    rsi = db.Column(db.Float)
    type = db.Column(db.String(5))
    timestamp = db.Column(db.DateTime)

En el archivo core/signal_engine.py, registra cada señal:

from web.app import db, SignalLog
from datetime import datetime

if signal:
    log = SignalLog(symbol=symbol, rsi=last['rsi'], type=tipo, timestamp=datetime.utcnow())
    db.session.add(log)
    db.session.commit()

8. Correr el Servidor Flask

cd web
python app.py

Y abre http://localhost:5000 para ver tu panel.


9. Opcionales y Mejoras

  • Dashboard con Streamlit: si prefieres dashboards rápidos con visualización gráfica
  • Exportar CSV desde el panel
  • Agregar login de usuario con Flask-Login
  • Modo oscuro y responsivo con Bootstrap 5

10. Conclusión

Felicitaciones, ahora tu bot de señales tiene una cara visible, un centro de comando, una interfaz digna de su potencial.

Has dado un salto cualitativo en tu sistema: pasaste de tener un bot en consola a un producto visual, escalable y fácil de gestionar, listo para expandirse a nuevos niveles.

Imagina que podrías usar este panel para vender acceso, crear una app, integrarlo con dashboards financieros o hasta exportarlo como producto SaaS.

Y esto apenas empieza.

Que tu bot sea invisible no significa que deba ser inaccesible. Ahora tiene un hogar. Un dashboard.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *