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.
