Historial de cambios
2026-09-11 — GitHub Actions + panel estático en Cloudflare + comandos por Telegram
- Hugging Face pasó a exigir PRO para Docker/Gradio: nuevo despliegue gratuito sin tarjeta.
bot job auto|execute|sync|snapshot|summary|backup|close: un job por invocación;autodecide por hora de Nueva York (ciclo si el mercado está abierto y no hubo hoy; cierre a partir de las 16:05 ET; sync en cualquier otro caso)..github/workflows/bot.yml: cron en UTC (9:35 ET y cada hora hasta el cierre), restaura y guarda la BD en la ramastate, publica el panel en la ramasite.- Comandos por Telegram (
engine/commands.py,bot telegram poll, job cada 5 min enbot run):/kill,/resume,/status,/nota,/watch,/unwatch,/help. Solo del chat configurado. bot site build: panel y documentación como HTML estático (sin formularios ni scripts) para Cloudflare Pages.- Guía
deploy/GITHUB_ACTIONS.md(secretos, primer lanzamiento, Cloudflare Pages + Access).
2026-09-11 — Hugging Face Spaces: bot y panel 24/7 sin tarjeta
engine/state_sync.pyybot state push|pull: la BD (y el archivo KILL) se guardan en la ramastatedel repositorio con copia consistente de SQLite; commit solo si cambió; al arrancar se restaura si la copia remota es más reciente.- Job
state_pushcada hora al :20 conSTATE_SYNC=true; también tras cada ciclo, el resumen diario y al pulsar kill/resume en el panel. deploy/huggingface/Dockerfile(único archivo que se sube al Space: clona el repo conGITHUB_TOKENy delega enrun.sh),run.sh(supervisor debot run+bot web) y guía paso a paso con cron-job.org para que el Space no se duerma.- Corrección crítica:
bot runfallaba al arrancar ('Job' object has no attribute 'next_run_time') al listar los jobs antes de iniciar el scheduler; ahora pregunta al trigger.
2026-09-11 — Servidor 24/7: instalador, backup diario y guía Oracle Cloud
deploy/install.sh: instalación idempotente en Ubuntu (paquetes, venv,.env, servicios).- Unidades systemd como plantillas
@usuario,SuccessExitStatus=3(reinicio por auto-update) y panel con--reload. - Job
backupa las 16:30 ET ybot backup: copia consistente detrading.dbenbackups/(API de backup de SQLite; se conservan 14). - Mensajes de inicio y resumen diario con el nombre de la máquina: un solo bot por cuenta.
deploy/SERVER.mdreescrito: Oracle Cloud paso a paso, Tailscale para el celular, problemas frecuentes.
2026-09-11 — El bot se actualiza solo (AUTO_UPDATE)
engine/updater.py:git fetch+merge --ff-only origin/main; reinstala con pip si cambiópyproject.toml; rechaza cambios locales sin commit y ramas divergentes; timeouts en git.- Job
updateenbot run(cada hora al :50, solo conAUTO_UPDATE=true): si hay código nuevo avisa por Telegram con los commits y sale con código 3 para que el supervisor lo relance. Todos los jobs corren en serie bajo un lock: nunca se reinicia a mitad de un ciclo. - Errores de actualización notificados una sola vez por mensaje distinto.
- Nuevo
bot update [--check];bot versiony la barra del panel muestran el estado. deploy/run-forever.cmdydeploy/web-forever.cmd(supervisores para Windows);SERVER.mdy README actualizados.- Operativa: los PR se fusionan en
maincuando CI está verde y el bot los recibe solo.
2026-09-11 — Panel: barra de estado, avisos y bot version
- El panel muestra una barra de estado con versión, commit corto, hora de arranque del
proceso, último ciclo, última sincronización, base de datos y carpeta
docs/. - Avisos automáticos: hay código nuevo en disco (reinicia
bot web), el bot no ha ejecutado ningún ciclo hoy, y no se encuentradocs/. - Rutas robustas:
docs/se resuelve desde el directorio actual o, si no está, desde la raíz del paquete instalado;docs/backtestsse crea si falta. __version__sale de los metadatos del paquete instalado; nuevobot version.- Las páginas de documentación indican su archivo fuente y cuándo se modificó.
- README: sección "El panel no se actualiza".
apschedulerpasa a dependencia principal (bot runla necesita; CI ypip install -e .no la instalaban).- Actualización automática: el navegador sondea
/api/heartbeatcadaWEB_REFRESH_SECONDS(30 s) y recarga la página cuando hay ciclo, sync, kill switch o docs nuevos;bot web --reloadreinicia el servidor al cambiar el código, vigilando la carpeta del paquete.
2026-09-11 — Más horas de mercado: catch-up, healthcheck, despliegue y backtest cripto
bot runejecuta el ciclo del día al arrancar si el mercado está abierto y aún no se hizo (catch-up); siempre sincroniza al arrancar.HEALTHCHECK_URL: ping a healthchecks.io tras cada ciclo y sincronización, para que un servicio externo avise si el bot muere.deploy/: unidades systemd para el bot y el panel, y guíaSERVER.md(Windows interino, Oracle Cloud Always Free, Raspberry Pi, Tailscale/túnel SSH).- Backtest cripto:
CryptoBarsProvider(barras de 1h/4h/1d, sin credenciales, cachéBTC-USD_4h.csv),commission_pctpor lado en ambos motores,calendar_daysen la estrategia (los fines de semana cuentan),bot backtest-portfolio --market cryptocon capital =CRYPTO_CAPITAL_PCT× cash,CRYPTO_MAX_OPEN_POSITIONSy benchmark BTC/USD. ReportesPORTFOLIO-CRYPTO-IS_*/-OOS_*. - Config nueva:
CRYPTO_*(módulo desactivado por defecto) yHEALTHCHECK_URL. - Decisión: el módulo cripto en vivo (stop-limit en Alpaca tras el fill, capital separado, jobs cada 4 h) solo se construye si el backtest supera a mantener BTC en Sharpe o drawdown con ≥ 30 operaciones fuera de muestra.
2026-09-10 — Primer backtest de cartera real y corrección de la ventana out-of-sample
- Reportes
PORTFOLIO-IS_2020-07-27_2022-12-30yPORTFOLIO-OOS_2021-11-29_2026-09-10commiteados; cierran la versión 1.1 de la estrategia. Resultado honesto: fuera de muestra +14.6 % (take_profit) con drawdown −2.9 % frente a +63.1 % de SPY. Protege capital, no bate al índice.take_profitse mantiene: trailing fue mejor en muestra y peor fuera de muestra. - Corrección: la ventana out-of-sample incluía los 400 días previos al corte (necesarios para
calentar indicadores) también en las métricas y en el benchmark. Ahora se recortan al corte
(
backtest.engine.trim). Los reportes OOS anteriores están ligeramente contaminados; el próximobot backtest-portfolio --splitlos regenera. - Nota de datos: el feed gratuito IEX empieza el 27-07-2020, no en 2019.
2026-09-10 — Fase 2 (código): scheduler y Telegram
bot run: APScheduler en hora de Nueva York con cuatro jobs de lunes a viernes: ejecución 9:35, sincronización de órdenes cada hora (10:05–16:05), snapshot de equity 16:10 y resumen diario 16:15. Un job que falla notifica y no mata el proceso.notify/telegram.py(POST con httpx, sin reintentos, nunca propaga errores) yNullNotifiercuando no hay token.bot notify-testpara probar.engine/runner.py:run_cycle_and_notify,run_sync_and_notify,take_equity_snapshot,send_daily_summary(incluye posiciones cerradas del día y day trades).bot cycleybot syncusan el mismo runner que el scheduler.- Se abandona el ciclo de 15 minutos: con decisiones diarias y stops en el bróker no aportaba.
- 14 tests nuevos (114 en total). Queda pendiente la observación: 3 días DRY_RUN + 10 días paper.
2026-09-10 — Fase 1b (parte 2): ciclo de vida de posiciones y sincronización
- Nueva tabla
positionscon máquina de estados: SIGNALED → SUBMITTED → OPEN → EXITING → CLOSED, más REJECTED y CANCELLED. Transiciones del bot y de Alpaca enexecution/lifecycle.py. execution/sync.py: en cada ciclo se consultan las órdenes por id, se registran fills y patas ejecutadas (stop / take-profit), se cierran posiciones que Alpaca cerró por su cuenta, se reconcilian posiciones ausentes y se cuentan los day trades reales para la regla anti-PDT.- Executor:
submit_exitcancela las patas abiertas del bracket (una vez, sin reintentos) antes de vender la cantidad real que reporta el bróker. Sin esto Alpaca rechazaba la venta. - Recalculo en ejecución: el último precio sustituye al cierre de la señal; stop y take-profit
se desplazan a la misma distancia y la cantidad se recalcula.
MAX_GAP_PCT(3 %) descarta la entrada si el precio se alejó demasiado. - Kill switch diario: la pérdida diaria activa
kill_until=hoy; el ciclo lo levanta al día siguiente. El kill manual sigue exigiendobot resume. - Modo trailing en vivo: en HOLD, si el stop calculado es mayor, se actualiza la pata stop del
bróker (
replace_stop); nunca baja. Las entradas trailing usan orden OTO (entrada + stop). FakeBrokersimula fills, vencimientos y patas ejecutadas para los tests.init_dbañade columnas nuevas a bases de datos SQLite existentes.- 17 tests nuevos del ciclo de vida (100 en total).
2026-09-10 — Fase 1b (parte 1): backtest de cartera y modo de salida trailing
bot backtest-portfolio: capital compartido,MAX_OPEN_POSITIONS, mismoposition_size, bracket simulado con mínimo/máximo del día y stop primero, selector por fuerza de tendencia (cierre / SMA200 − 1). ReportePORTFOLIO_*.md+ PNG con curva vs benchmark y nota explícita de sesgo de supervivencia.--splitgeneraPORTFOLIO-IS_*yPORTFOLIO-OOS_*.- Estrategia:
EXIT_MODE=trailing(solo stop, que sube con el máximo alcanzado menosSTOP_ATR_MULT× ATR).Signallleva ahoraatr;PositionInfollevastop_priceyhigh_water. El motor por símbolo también soporta trailing. - Sin reglas de pérdida diaria ni drawdown en esta primera versión, a propósito.
2026-09-10 — Revisión pre-paper: correcciones de plan y reglas
Una revisión externa detectó defectos que romperían el paper trading. Decisiones:
- Se mantienen las órdenes bracket de Alpaca: el stop vive en el bróker, no en el proceso del
bot. En la Fase 6 el capital mínimo pasa a ~1 500–2 000 USD y se filtran símbolos cuyo precio no
cabe en
MAX_POSITION_PCT× equity. - Nueva Fase 1b antes del paper: backtest de cartera (capital compartido, límite de
posiciones, selector, comparación take-profit vs trailing) y ciclo de vida de posiciones
(cancelar patas del bracket antes de vender, sincronizar fills, recalcular stop y cantidad en
ejecución con
MAX_GAP_PCT, kill switch diario con expiración, conteo real de day trades). - Horario de la Fase 2: ejecución 9:35 ET, sincronización cada hora, snapshot 16:10, resumen 16:15. Se abandona el ciclo de 15 minutos.
MIN_CASH_PCTeliminado del gestor de riesgo: con 5 posiciones de 10 % nunca actuaba.- Barras diarias ajustadas por splits (
adjustment=SPLIT); la caché cambia a*_1d_split.csv. - Documentado "stop primero" cuando mínimo y máximo tocan ambos niveles en la misma barra.
- Retirado el filtro de earnings (sin fuente gratuita). El plan ya no cita
backtesting.py. - Nuevos parámetros
EXIT_MODEyMAX_GAP_PCT(efectivos en Fase 1b).
<details><summary>Archivo: evaluación original de la web (sección 7 del plan)</summary>
| Opción | Veredicto |
|---|---|
| FastAPI + Jinja2 + HTMX | Recomendada: mismo proceso y modelos que el bot, casi sin JS, fácil de autenticar |
Dashboard estático vanilla-JS (estilo SPA) contra /api/* |
Alternativa válida si prefiere JS; localStorage no sirve porque la fuente de verdad es la BD del bot |
| Streamlit | Útil para explorar backtests, no como dashboard 24/7 |
| CSV / Notion | Complemento para notas largas, no sustituto (sin estado en vivo ni kill switch) |
MVP en orden: estado + kill switch → bitácora de decisiones (lo más valioso) → journal + watchlist → métricas → logs. No al inicio: velas interactivas, websockets, multiusuario.
</details>
2026-09-10 — Fase 3: panel operativo local y documentación viva
bot websirve un panel FastAPI + Jinja2 en127.0.0.1:8000con autenticación básica opcional.- Operativo: dashboard (equity, P&L, posiciones, órdenes, decisiones, kill switch con
confirmación), bitácora con filtros, journal, watchlist, métricas (curva de equity SVG,
drawdown, conteos), logs y API JSON (
/api/status,/api/decisions,/health). - Documentación: plan, historial con
git log, estrategia con parámetros leídos de la configuración real, estructura con el árbol real desrc/, índice de backtests y tablero de mejoras (idea / probada / desplegada / descartada) sobre el journal. - Nuevos
docs/STRATEGY.mdydocs/ARCHITECTURE.md. Un test verifica que STRATEGY.md mencione todos los parámetros de estrategia y riesgo deconfig.py. - Se pospone la Fase 2 (scheduler + Telegram); el trabajo parcial queda en la rama
feat/phase-2-scheduler.
Una entrada por mejora. Cada cambio de estrategia o de reglas de riesgo debe venir con su
backtest en docs/backtests/ y con STRATEGY.md actualizado.
2026-09-10 — Plan revisado con documentación viva y universo S&P 500
- La Fase 3 (web) incorpora una sección de documentación: plan, historial de cambios, estrategia, estructura, índice de backtests y mejoras propuestas.
- Nueva Fase 4 para ampliar el universo al S&P 500 (lista de constituyentes, datos por lotes, selector de candidatos, backtest de cartera, sesgo de supervivencia).
- Hardening pasa a Fase 5 y la decisión de dinero real a Fase 6.
- Canal de notificaciones confirmado: Telegram.
2026-09-10 — Fase 1: datos históricos y backtesting
- Descarga de barras diarias con caché CSV en
data/cache/. - Backtester propio barra a barra que reutiliza
SmaCrossStrategyyposition_size(). Ejecución en la apertura siguiente con slippage 0.05 % y bracket intradía. - Métricas (retorno, CAGR, drawdown, Sharpe, win rate, expectancy, exposición, buy & hold),
reporte markdown y gráfico PNG. Comando
bot backtestcon--split. - Cambio de estrategia: entrada permitida hasta 5 barras después del cruce
(
entry_window=5). Antes solo entraba en la barra exacta del cruce y perdía señales válidas cuando el precio superaba la SMA200 unos días después.
2026-09-10 — Fase 0: base del proyecto
- Configuración con
pydantic-settings; paper yDRY_RUNpor defecto; el modo live exigeI_UNDERSTAND_LIVE_TRADING=true. - Cliente Alpaca (
AlpacaBroker) y bróker en memoria (FakeBroker) para tests. - Indicadores SMA/EMA/ATR/RSI en pandas puro.
- Estrategia
sma_crossconreasonlegible en cada señal. - Reglas de riesgo puras y
RiskManager; executor idempotente porclient_order_id. - Ciclo completo con bitácora en SQLite; CLI
bot status|init-db|signal|cycle|kill|resume. - Corrección: el
.gitignoreexcluíasrc/trading_bot/data; ahora solo ignora/data/raíz.
2026-09-10 — Repositorio propio
- El proyecto sale de la carpeta
trading-bot/de HabitOS y pasa a su propio repositorio con todo el historial de commits. - Se añade CI en GitHub Actions: ruff + pytest en cada push y PR.