main.py
Fuente de datos · Sincronización continuaEs el cerebro de sincronización del sistema. Se conecta a MySQL y a la API de Bybit para mantener actualizado el archivo operaciones_activas.json cada 2 segundos. Este JSON es la fuente de datos que consumen los otros dos scripts. También actualiza el precio de breakeven real de cada posición en la base de datos cada 5 minutos consultando a Bybit directamente.
- Consulta la tabla precios para obtener cotizaciones actuales, tasa de financiamiento y countdown del funding
- Hace JOIN entre aurixalpha y token para obtener el logo de cada activo
- Filtra únicamente registros con
estado = 'Abierta'ordenados por ID descendente - Construye un objeto JSON por cada operación con todos sus campos: entrada, TPs, SL, precio actual, BE, modelo, temporalidad, etc.
- Escribe el resultado en
operaciones_activas.jsonsobreescribiendo la versión anterior - Imprime en consola el timestamp y la cantidad de activos procesados
- Obtiene la tabla de precios actuales desde MySQL como fallback para BEs vacíos
- Consulta todos los registros con
estado = 'Abierta'para obtener sus IDs y BEs registrados - Recorre todas las posiciones abiertas en Bybit con paginación (límite 100 por página)
- Si
breakEvenPriceestá vacío o es cero, usa el precio actual del activo como BE - Compara el BE de Bybit con el registrado en la BD y solo actualiza si hay diferencia
- Usa el ID del registro (no orden_serial) en el WHERE del UPDATE para mayor precisión
- Genera una línea de log en
registros/{id}.txtpor cada actualización realizada
- Crea la carpeta
registros/si no existe - Nombre del archivo:
{id_registro}.txt(ej:42.txt) - Cada línea incluye timestamp en formato
YYYY-MM-DD HH:MM:SSy la etiqueta MAIN - Modo append — no sobreescribe el historial previo
- Usa
parse_mode: Markdownpara formato de texto - Apunta específicamente al THREAD_ERRORES (hilo 4)
- Se activa ante errores en
update_data(),actualizar_breakeven_logic()y errores fatales - Fallo silencioso si Telegram no responde (no interrumpe el loop)
- Limpia pantalla con
cls(Windows) oclear(Linux/Mac) - Banner en color cyan con información del proyecto, estado y destino del JSON
- Se ejecuta una sola vez al arrancar el script
DB_CONFIGactualizar_breakeven_logic() sin esperar los 5 minutosupdate_data() cada 2 segundosactualizar_breakeven_logic() en paralelo al loopKeyboardInterrupt cierra la conexión DB limpiamente y terminaId · Activo · Direccion · Entrada · Precio_Actual · TP1 · TP2 · TP3 · SL · Fecha_inicio · Modelo · Temporalidad · Estado_Monitor · tasa_financiamiento · tiempo_tasa_financiamiento · precio_be · precio_be_colocado · precio_be_plus · orden_bybit_id · estado_orden_bybit · 12h · cambio_direccion
monitor.py
Motor de alertas · Solo opera sobre modelo BUZZ
Es el motor de decisiones del sistema. Lee el JSON cada 1 segundo, filtra únicamente las operaciones del modelo BUZZ y evalúa si el precio actual ha alcanzado algún nivel relevante (TP1, TP2, TP3, SL). Cuando detecta un evento, actualiza el estado_monitor en MySQL y envía una notificación a Telegram. No ejecuta órdenes en Bybit — eso le corresponde a Sentinel.
- Ignora operaciones que ya tienen estado final:
tp1 completo,tp2 completo,tp3 completo,be completo,sl - Determina el SL vigente según el estado actual: en
beusaprecio_be, entp1usa precio de TP1, en otros usa SL original - Si precio toca el SL vigente → cierra con el estado final correspondiente y notifica
- Si precio alcanza TP3 → marca como
tp3 completoy notifica con ROI - Si precio alcanza TP2 con TP3 activo → mueve estado a
tp1para proteger en TP1 - Si precio alcanza TP2 sin TP3 → marca como
tp2 completoy notifica con ROI - Si precio alcanza TP1 desde estado
abierta→ mueve estado abepara que Sentinel coloque el SL
- Limpia la pantalla en cada ciclo para simular un dashboard live
- Muestra: ID, activo, dirección, precio de entrada, precio actual con PnL, TP1/TP2/TP3, SL vigente, funding rate, countdown del funding, horas activa y estado
- El PnL se calcula con apalancamiento x5:
((actual - entrada) / entrada) × 100 × 5 - Colores: verde si va en ganancia, rojo si va en pérdida
- El SL que muestra es el vigente según el estado (BE, TP1 o SL original)
- Estados con iconos: ⏳ Abierta · 🛡️ BE · 🎯 TP1 · ✅ TP2 · 💎 TP3 · 🏁 Completo · 🛑 SL
- Abre una conexión nueva por cada llamada (no reutiliza conexión persistente)
- Ejecuta
UPDATE aurixalpha SET estado_monitor = %s WHERE id = %s - Registra la conexión en
logs/db_conexiones.log - Retorna
Truesi el update fue exitoso,Falsesi hubo error - Ante error envía alerta detallada a Telegram por el hilo de errores
- Solo actualiza si
tp_icoaún no es'Si'(condición en el WHERE) - Se llama únicamente al alcanzar TP1 desde estado
abierta - Sirve para registrar que la operación tocó al menos su primer objetivo
- Archivo:
registros/{id_op}.txt(ruta un nivel arriba del directorio del script) - Formato:
timestamp, MONITOR: mensaje_del_cambio - Modo append — preserva todo el historial de eventos de la operación
- Errores de escritura van a
logs/error_sistema_registros.log
- Usa
parse_mode: HTMLpara formato (diferente a main.py que usa Markdown) - Por defecto envía al THREAD_SEÑALES; errores van al THREAD_ERRORES
- Respuestas no-200 se registran en
logs/error_telegram_api.log - Fallos de red se registran en
logs/error_red.log
- Captura el traceback completo con
traceback.format_exc() - Escapa los caracteres HTML del traceback (
<y>) - Incluye los últimos 400 caracteres del traceback en un bloque
<pre> - Omite el detalle técnico si el error no tiene información (NoneType)
- Hasta 3 intentos con 100ms de espera entre cada uno
- Diseñado para tolerar que
main.pyesté escribiendo el archivo al mismo tiempo - Si los 3 intentos fallan retorna lista vacía (no lanza excepción)
- LONG:
((actual - entrada) / entrada) × 100 × 5 - SHORT:
((entrada - actual) / entrada) × 100 × 5 - Retorna 0 si entrada es 0 para evitar división por cero
- Acepta timestamps en segundos o milisegundos (detecta automáticamente)
- Calcula la diferencia con el tiempo actual
- Si el countdown ya pasó retorna
"0m"
| Condición | Estado previo | Acción | Nuevo estado |
|---|---|---|---|
| precio ≤ SL (LONG) o precio ≥ SL (SHORT) | abierta | Actualiza BD + notifica Telegram con ROI | sl |
| precio ≤ precio_be (LONG) o ≥ (SHORT) | be | Actualiza BD + notifica Telegram con ROI | be completo |
| precio ≤ TP1 (LONG) o ≥ (SHORT) como SL | tp1 | Actualiza BD + notifica Telegram con ROI | tp1 completo |
| precio ≥ TP1 (LONG) o ≤ (SHORT) | abierta | Actualiza BD + marca tp_ico + notifica "SL a BE" | be |
| precio ≥ TP2 (LONG), hay TP3 | be / abierta | Actualiza BD + notifica "SL protegido en TP1" | tp1 |
| precio ≥ TP2 (LONG), sin TP3 | be / abierta | Actualiza BD + notifica con ROI final | tp2 completo |
| precio ≥ TP3 (LONG) o ≤ (SHORT) | tp1 | Actualiza BD + notifica con ROI final | tp3 completo |
sentinel.py
Motor de ejecución · Único script que opera en BybitEs el ejecutor de órdenes del sistema. Es el único de los tres scripts que envía comandos reales a Bybit (colocar SL, cerrar posiciones, ajustar TPs). Opera en un loop de 2 segundos y ejecuta hasta 4 módulos independientes, cada uno con un interruptor ON/OFF configurable. Toda acción queda registrada en logs locales y en el archivo de registro por ID.
| Módulo | Variable | Estado | Descripción |
|---|---|---|---|
| Sincronización de estados | MODULO_SINC_ESTADOS | ON | Detecta cuando una orden Pendiente pasa a Abierta en Bybit |
| Auditoría de posiciones | MODULO_AUDITORIA | ON | Compara posiciones del JSON contra las reales en Bybit cada 5 min |
| Cambio de dirección | MODULO_CAMBIO_DIRECCION | ON | Cierra posiciones a mercado cuando cambio_direccion = 'Si' |
| Tiempo medio (12h) | MODULO_12_HORAS | ON | Gestiona operaciones que superan 12 horas activas |
| Breakeven engine | MODULO_BREAKEVEN | ON | Coloca y ajusta el SL en Bybit al precio de breakeven |
- Lee el JSON con hasta 10 reintentos (espera 500ms entre cada uno) para máxima robustez
- Llama a
sincronizar_estados_db()antes de procesar operaciones individuales - Itera cada operación ejecutando: Cambio Dirección → 12 Horas → Breakeven (en ese orden)
- Si hubo algún cambio en memoria, reescribe el JSON al final del ciclo
- Solo actúa en operaciones con modelo
BUZZ,Estado_Monitor = 'Abierta'yestado_orden_bybit = 'Pendiente' - Consulta a Bybit si hay posición abierta con size > 0 para ese símbolo
- Si la hay: actualiza
estado_orden_bybit = 'Abierta'en MySQL - Registra el cambio en el archivo de registro del ID
- Notifica la entrada al grupo de Telegram
- Calcula los decimales necesarios desde el precio de entrada para formatear correctamente
- Consulta el SL actual en Bybit antes de enviar la orden
- Si el SL en Bybit ya coincide con el deseado, no hace nada (evita órdenes innecesarias)
- Ejecuta
set_trading_stopconslTriggerBy: MarkPriceytpslMode: Full - Distingue entre protección inicial y ajuste posterior para el mensaje de log
- Maneja el error 34040 de Bybit ("not modified") como estado OK, no como error
- Notifica por Telegram al hilo MONITOR con el precio aplicado
- Registra el evento en el archivo de registro del ID
- Lee el JSON con hasta 10 reintentos antes de auditar
- Extrae todos los símbolos con
estado_orden_bybit = 'Abierta'del JSON - Recorre todas las posiciones reales de Bybit con paginación completa
- Compara ambas listas y detecta símbolos en el JSON que ya no existen en Bybit
- Si hay discrepancias, envía un informe al hilo MONITOR con la lista de símbolos afectados
- Si todo está correcto, registra "Auditoría OK" en el log con la cantidad validada
- Lee el campo
cambio_direcciondel JSON para cada operación - Consulta Bybit para obtener el side actual (Buy/Sell) y el size de la posición
- Ejecuta una orden
Marketopuesta conreduceOnly: Truepara cerrar - Si el cierre es exitoso: notifica a Telegram, actualiza BD a
cambio_direccion = 'Completa'y continúa al siguiente ciclo - Registra el evento en el archivo de registro del ID
- Solo actúa si
12h != 'Activo',estado_orden_bybit = 'Abierta'y no hay estado "completo" - Calcula la diferencia entre ahora y
fecha_iniciocon zona horaria Bogotá - Escenario A — precio ya superó TP1: cierra la posición a mercado inmediatamente, actualiza estado a
tp1 completoy notifica "Cierre a mercado (Precio > TP1)" - Escenario B — precio aún no llegó a TP1: ajusta el Take Profit de Bybit al valor de TP1 para que cierre automáticamente ahí, notifica "Tiempo medio activado"
- En ambos casos: actualiza
12h = 'Activo'en BD y registra el evento
- Solo actúa en operaciones
BUZZconEstado_Monitoren'be'o'tp1'yestado_orden_bybit = 'Abierta' - Compara
precio_be(calculado por main.py desde Bybit) conprecio_be_colocado(el último que Sentinel colocó) - Si son iguales: no hace nada
- Si son diferentes: llama a
colocar_sl_be()y si tiene éxito actualiza en BD:protegida = 'Si',Estado_Monitor = 'be',precio_be_colocado = nuevo_valor - Determina si es ajuste (
precio_be_colocadoya tenía valor) o protección inicial
- Tipos:
INFO·OK·ERROR·WARN·CRIT·DB·AUDIT - Cada tipo tiene su propio icono (ℹ️ ✅ ❌ ⚠️ 🔥 🗄️ 🔍)
- Los tipos
ERRORyCRITtambién envían alerta a Telegram automáticamente - Archivo de log:
logs/be.logcon timestamps completos
- Archivo:
registros/{id_op}.txt(un nivel arriba del directorio del script) - Formato:
timestamp, Auditor: descripción_del_cambio - Errores de escritura se registran en el log principal, no interrumpen el ciclo
- Elimina caracteres no numéricos excepto punto y signo menos
- Maneja
None, strings vacíos y valores malformados - Retorna
Nonesi el valor no es convertible (no lanza excepción)
- Encabezado diferente según sea protección inicial o ajuste posterior
- Incluye activo, precio colocado e ID de la operación
- Errores HTTP se registran en el log con el detalle de la respuesta
- Mensaje: "POSICIÓN ABIERTA" con nombre del activo e ID
- Se envía al hilo MONITOR del grupo de Telegram
- Solo se dispara una vez por operación gracias a la condición en sincronizar_estados_db
- Registrado con
signal.signal(signal.SIGINT, handler_salir) - Registra el mensaje "Cerrando Sentinel de forma segura" en el log
- Termina el proceso con
sys.exit(0)
operaciones_activas.json existahubo_cambio = Truehubo_cambio es True, reescribe el JSON con los datos actualizados en memoria.envauditar_posiciones_bybit() y actualiza el timestampejecutar_ciclo() y muestra el timestamp con "Sentinel latiendo... OK" en consolaCRIT y el loop continúa sin interrumpirse- MAIN — cambios de precio_be desde main.py
- MONITOR — cambios de estado desde monitor.py
- Auditor — acciones de Bybit desde sentinel.py
- Todos en modo append — el historial nunca se borra
be.log— todas las acciones del engine con tipo y timestampdb_conexiones.log— cada conexión a MySQL
error_telegram_api.log— respuestas HTTP no-200 de Telegramerror_red.log— fallos de conexión de rederror_sistema_registros.log— errores al escribir archivos de registrodb_conexiones.log— conexiones a MySQL