javitechjkd/backtestingv2
0
1"""2AriasCampos Backtester3Aplicación de backtesting para algoritmos de trading estructural4 5Algoritmos disponibles:6- FAST (AriasCampos 5.2): Doble estructura simultánea7- SLOW (AriasCampos Slow): Estructura única con sensibilidad8 9Autor: Javier10Versión: 2.0 - Arquitectura Modular11"""12 13import streamlit as st14import sys15import os16import logging17from pathlib import Path18 19# Añadir el directorio raíz al path para permitir imports absolutos20root_dir = Path(__file__).resolve().parent.parent21if str(root_dir) not in sys.path:22 sys.path.insert(0, str(root_dir))23 24# =============================================================================25# CONFIGURACIÓN DE LOGGING - Evitar duplicados26# =============================================================================27# Deshabilitar loggers de terceros28for logger_name in ['streamlit', 'urllib3', 'matplotlib', 'PIL']:29 logging.getLogger(logger_name).propagate = False30 logging.getLogger(logger_name).handlers = []31 32from backtesting_app.ui import render_single_asset_tab, render_multi_asset_tab, render_strategies_tab33from backtesting_app.ui.screener import render_screener_tab34 35# =============================================================================36# CONFIGURACIÓN DE LA PÁGINA37# =============================================================================38 39st.set_page_config(40 page_title="AriasCampos Backtester",41 page_icon="📈",42 layout="wide",43 initial_sidebar_state="expanded"44)45 46# =============================================================================47# ESTILOS CSS48# =============================================================================49 50st.markdown("""51<style>52 /* Tema oscuro general */53 .stApp {54 background-color: #0e1117;55 }56 57 /* Headers */58 h1, h2, h3 {59 color: #ffffff !important;60 }61 62 h5 {63 color: #ffffff !important;64 font-size: 1.1rem !important;65 margin-bottom: 0.5rem !important;66 }67 68 /* Sidebar */69 .css-1d391kg {70 background-color: #131722;71 }72 73 /* Métricas */74 [data-testid="stMetricValue"] {75 font-size: 1.8rem;76 font-weight: bold;77 color: #2962ff !important;78 }79 80 [data-testid="stMetricLabel"] {81 color: #787b86;82 font-size: 0.95rem;83 }84 85 [data-testid="stMetricDelta"] {86 font-size: 0.9rem;87 }88 89 /* Botones - Mejora principal */90 .stButton {91 min-height: 60px;92 margin-bottom: 0.5rem;93 }94 95 .stButton > button {96 background: linear-gradient(135deg, #2962ff 0%, #1e4bd8 100%);97 color: white;98 border: 2px solid #2962ff;99 padding: 0.75rem 1rem;100 border-radius: 6px;101 font-weight: bold;102 font-size: 0.95rem;103 height: 100%;104 width: 100%;105 transition: all 0.3s ease;106 white-space: pre-wrap;107 word-wrap: break-word;108 }109 110 .stButton > button:hover {111 background: linear-gradient(135deg, #1e4bd8 0%, #2962ff 100%);112 box-shadow: 0 4px 12px rgba(41, 98, 255, 0.4);113 transform: translateY(-2px);114 border-color: #2962ff;115 }116 117 .stButton > button:active {118 background: linear-gradient(135deg, #0d47a1 0%, #1e4bd8 100%);119 box-shadow: 0 2px 6px rgba(41, 98, 255, 0.2);120 transform: translateY(0);121 }122 123 /* Tabs */124 .stTabs [data-baseweb="tab-list"] {125 gap: 8px;126 background-color: transparent;127 border-bottom: 2px solid #1e222d;128 padding: 0;129 }130 131 .stTabs [data-baseweb="tab"] {132 background-color: #1e222d;133 border-radius: 6px 6px 0 0;134 padding: 12px 24px;135 color: #787b86;136 border: none;137 font-weight: 600;138 transition: all 0.3s ease;139 }140 141 .stTabs [data-baseweb="tab"]:hover {142 background-color: #262d38;143 color: #b0b5be;144 }145 146 .stTabs [aria-selected="true"] {147 background-color: #2962ff;148 color: white;149 box-shadow: 0 2px 8px rgba(41, 98, 255, 0.3);150 }151 152 /* DataFrames */153 .dataframe {154 background-color: #131722 !important;155 }156 157 /* Expanders */158 .streamlit-expanderHeader {159 background-color: #1e222d;160 border-radius: 4px;161 }162 163 /* Info boxes */164 .stAlert {165 background-color: #1e222d;166 border: 1px solid #2962ff;167 border-radius: 6px;168 padding: 1rem;169 }170 171 /* Dividers */172 hr {173 background-color: #1e222d !important;174 border: none;175 height: 2px;176 margin: 1rem 0;177 }178 179 /* Inputs */180 .stSelectbox, .stMultiSelect, .stNumberInput, .stSlider {181 color: white;182 }183 184 /* Caption text */185 small, .stCaption {186 color: #787b86 !important;187 }188 189 /* Text content */190 p {191 color: #b0b5be;192 }193 194 /* Success messages */195 .stSuccess {196 background-color: rgba(41, 98, 255, 0.1) !important;197 border: 1px solid #2962ff !important;198 border-radius: 6px;199 padding: 1rem;200 }201 202 /* Warning messages */203 .stWarning {204 background-color: rgba(255, 193, 7, 0.1) !important;205 border: 1px solid #ffc107 !important;206 border-radius: 6px;207 padding: 1rem;208 }209 210 /* Error messages */211 .stError {212 background-color: rgba(255, 52, 52, 0.1) !important;213 border: 1px solid #ff3434 !important;214 border-radius: 6px;215 padding: 1rem;216 }217 218 /* Info messages */219 .stInfo {220 background-color: rgba(33, 150, 243, 0.1) !important;221 border: 1px solid #2196f3 !important;222 border-radius: 6px;223 padding: 1rem;224 }225 226 /* Footer */227 .footer {228 position: fixed;229 bottom: 0;230 left: 0;231 right: 0;232 background-color: #131722;233 padding: 10px;234 text-align: center;235 font-size: 0.8rem;236 color: #787b86;237 }238</style>239""", unsafe_allow_html=True)240 241# =============================================================================242# HEADER243# =============================================================================244 245st.markdown("""246<div style="text-align: center; padding: 1rem 0;">247 <h1 style="margin: 0;">📈 AriasCampos Backtester</h1>248 <p style="color: #787b86; margin: 0.5rem 0 0 0;">249 Sistema de Backtesting para Algoritmos de Trading Estructural250 </p>251</div>252""", unsafe_allow_html=True)253 254# =============================================================================255# SIDEBAR GLOBAL256# =============================================================================257from datetime import datetime, timedelta258from backtesting_app.core.data_loader import DATA_SOURCES259 260with st.sidebar:261 st.header("🔧 Configuración Global")262 263 # Algoritmo264 algorithm_choice = st.selectbox(265 "🤖 Algoritmo",266 options=['FAST', 'SLOW'],267 index=0,268 key="global_algo",269 help="FAST: AriasCampos 5.2 (2 estructuras), SLOW: AriasCampos Slow (1 estructura)"270 )271 st.session_state['config_algorithm'] = algorithm_choice272 273 st.markdown("---")274 275 # Timeframe276 st.subheader("⏱️ Timeframe")277 timeframes = {278 '1h': '1 Hora',279 '4h': '4 Horas',280 '1d': '1 Día',281 '1wk': '1 Semana',282 '1mo': '1 Mes'283 }284 timeframe = st.selectbox(285 "Intervalo",286 options=list(timeframes.keys()),287 format_func=lambda x: timeframes[x],288 index=4, # 1mo por defecto289 key="global_timeframe"290 )291 st.session_state['config_timeframe'] = timeframe292 293 # Período - DROPDOWN en lugar de botones294 st.subheader("📅 Período")295 period_options = {296 '1m': 'Último Mes',297 '3m': '3 Meses',298 '6m': '6 Meses',299 '1y': '1 Año',300 '2y': '2 Años',301 '5y': '5 Años',302 '10y': '10 Años',303 'max': 'Máximo disponible'304 }305 306 selected_period = st.selectbox(307 "Período de datos",308 options=list(period_options.keys()),309 format_func=lambda x: period_options[x],310 index=4, # 2 años por defecto311 key="global_period"312 )313 314 # Calcular fechas según período315 end_date = datetime.now()316 period_days = {317 '1m': 30, '3m': 90, '6m': 180, '1y': 365,318 '2y': 730, '5y': 1825, '10y': 3650, 'max': 10000319 }320 start_date = end_date - timedelta(days=period_days[selected_period])321 322 st.session_state['config_start_date'] = start_date323 st.session_state['config_end_date'] = end_date324 st.caption(f"📊 {start_date.strftime('%Y-%m-%d')} → {end_date.strftime('%Y-%m-%d')}")325 326 st.markdown("---")327 328 # Fuente de datos - Ahora fija a yfinance329 st.session_state['config_source'] = 'yahoo'330 331 # Twelve Data API Key (con clave por defecto)332 st.subheader("🔑 Twelve Data")333 st.caption("✅ API Key configurada - Historiales hasta 10 años en timeframes de 1h/4h")334 335 # API key por defecto336 DEFAULT_API_KEY = "5e4ae0d60bcc452292708eef93b4de48"337 338 # Permitir override si el usuario quiere usar otra339 with st.expander("🔧 Cambiar API Key (opcional)", expanded=False):340 twelve_key = st.text_input(341 "API Key personalizada",342 type="password",343 help="Si quieres usar tu propia API key de Twelve Data",344 placeholder="Dejar vacío para usar la API key por defecto"345 )346 347 # Usar la API key ingresada o la por defecto348 st.session_state['config_api_key'] = twelve_key if twelve_key else DEFAULT_API_KEY349 350 st.markdown("---")351 352 # Gestión de Capital353 st.subheader("💰 Capital")354 355 initial_capital = st.number_input(356 "Capital Inicial ($)",357 min_value=100,358 max_value=10000000,359 value=10000,360 step=1000,361 key="global_capital"362 )363 st.session_state['config_capital'] = initial_capital364 365 risk_percent = st.slider(366 "Riesgo por Trade (%)",367 min_value=0.1,368 max_value=10.0,369 value=1.0,370 step=0.1,371 key="global_risk"372 )373 st.session_state['config_risk'] = risk_percent374 375 commission = st.number_input(376 "Comisión (%)",377 min_value=0.0,378 max_value=1.0,379 value=0.1,380 step=0.01,381 key="global_commission"382 )383 st.session_state['config_commission'] = commission384 385 # Dirección de trades386 direction_filter = st.selectbox(387 "Dirección de Trades",388 options=['LONG y SHORT', 'Solo LONG', 'Solo SHORT'],389 key="global_direction"390 )391 st.session_state['config_direction'] = direction_filter392 393 st.markdown("---")394 395 # Parámetros del algoritmo (expandible)396 with st.expander(f"⚙️ Parámetros {algorithm_choice}", expanded=True):397 if algorithm_choice == 'FAST':398 lookbehind = st.number_input("Lookbehind", 0, 20, 0, key="global_lb",399 help="Barras hacia atrás para buscar máximos/mínimos")400 stop_resets = st.checkbox("Stop resets support", True, key="global_srs",401 help="Si el stop resetea los niveles de soporte/resistencia")402 break_margin = st.number_input("Break Margin (%)", 0.0, 5.0, 0.0, 0.1, key="global_bm",403 help="Margen adicional para confirmar ruptura")404 405 # Márgenes por timeframe406 st.markdown("##### Margen S/R por Timeframe")407 margin_defaults = {'1h': 0.15, '4h': 0.3, '1d': 0.7, '1wk': 1.4, '1mo': 3.0}408 margin = st.number_input(409 f"Margen {timeframe} (%)",410 min_value=0.0, max_value=10.0,411 value=margin_defaults.get(timeframe, 0.3),412 step=0.05, key="global_margin"413 )414 415 st.session_state['config_params'] = {416 'lookbehind': lookbehind,417 'stop_resets_support': stop_resets,418 'break_margin': break_margin,419 f'margin_{timeframe.replace("1", "")}': margin420 }421 else: # SLOW422 lookbehind = st.number_input("Lookbehind", 0, 20, 0, key="global_lb",423 help="Barras hacia atrás para buscar máximos/mínimos")424 sensibilidad = st.number_input("Sensibilidad", 1, 10, 2, key="global_sens",425 help="Rupturas consecutivas para cambiar tendencia")426 offset = st.number_input("Offset", 0, 10, 1, key="global_offset",427 help="Desplazamiento para buscar máximos/mínimos")428 429 # Márgenes Long/Short por timeframe430 st.markdown("##### Márgenes Long")431 margin_defaults = {'1h': 0.15, '4h': 0.3, '1d': 0.7, '1wk': 1.4, '1mo': 3.0}432 default_margin = margin_defaults.get(timeframe, 0.3)433 434 margin_long_support = st.number_input(435 f"Soporte Long {timeframe}", 0.0, 10.0, 0.0, 0.05, key="global_mls"436 )437 margin_long_resistance = st.number_input(438 f"Resistencia Long {timeframe}", 0.0, 10.0, default_margin, 0.05, key="global_mlr"439 )440 441 st.markdown("##### Márgenes Short")442 margin_short_support = st.number_input(443 f"Soporte Short {timeframe}", 0.0, 10.0, default_margin, 0.05, key="global_mss"444 )445 margin_short_resistance = st.number_input(446 f"Resistencia Short {timeframe}", 0.0, 10.0, 0.0, 0.05, key="global_msr"447 )448 449 st.session_state['config_params'] = {450 'lookbehind': lookbehind,451 'sensibilidad': sensibilidad,452 'offset': offset,453 'margin_long_support': margin_long_support,454 'margin_long_resistance': margin_long_resistance,455 'margin_short_support': margin_short_support,456 'margin_short_resistance': margin_short_resistance457 }458 459# =============================================================================460# TABS PRINCIPALES461# =============================================================================462 463tab1, tab2, tab3, tab4, tab5 = st.tabs([464 "📊 Activo Único",465 "🌐 Multi-Activo",466 "🔍 Screener",467 "📈 Estrategias",468 "ℹ️ Documentación"469])470 471# Tab 1: Activo Único472with tab1:473 render_single_asset_tab()474 475# Tab 2: Multi-Activo476with tab2:477 render_multi_asset_tab()478 479# Tab 3: Screener480with tab3:481 render_screener_tab()482 483# Tab 4: Estrategias484with tab4:485 render_strategies_tab()486 487# Tab 5: Documentación488with tab5:489 st.header("📖 Documentación")490 491 st.markdown("""492 **AriasCampos Backtester** es una herramienta profesional de backtesting para algoritmos de trading 493 estructural. Soporta múltiples fuentes de datos (Yahoo Finance, YahooQuery) y ofrece un análisis 494 detallado de métricas de rendimiento y visualización estilo TradingView.495 496 ---497 498 ## 🚀 Algoritmo FAST (AriasCampos 5.2)499 500 ### Concepto501 El algoritmo FAST mantiene **dos estructuras simultáneas**: una alcista y una bajista. 502 Esto permite capturar cambios de tendencia más rápidamente.503 504 ### Parámetros505 506 | Parámetro | Descripción | Rango | Default |507 |-----------|-------------|-------|---------|508 | `lookbehind` | Barras hacia atrás para buscar máximos/mínimos | 1-20 | 10 |509 | `stop_resets_support` | Si el stop resetea niveles S/R | true/false | true |510 | `break_margin` | Margen adicional para confirmar ruptura | 0-5% | 0% |511 | `margin_XH` | Margen de S/R por timeframe | 0-10% | Variable |512 513 ### Lógica514 1. Inicializa dos estructuras en la primera barra515 2. La estructura alcista se actualiza cuando el precio rompe resistencia516 3. La estructura bajista se actualiza cuando el precio rompe soporte517 4. Se genera señal LONG cuando la estructura alcista cambia a bullish518 5. Se genera señal SHORT cuando la estructura bajista cambia a bearish519 520 ---521 522 ## 🐢 Algoritmo SLOW (AriasCampos Slow Strategy)523 524 ### Concepto525 El algoritmo SLOW mantiene **una única estructura** que cambia según la tendencia actual. 526 Requiere múltiples rupturas consecutivas antes de cambiar de tendencia, lo que filtra el ruido.527 528 ### Parámetros529 530 | Parámetro | Descripción | Rango | Default |531 |-----------|-------------|-------|---------|532 | `sensibilidad` | Rupturas consecutivas necesarias | 1-10 | 2 |533 | `offset` | Desplazamiento para buscar niveles | 0-10 | 1 |534 | `margin_long_support` | Margen de soporte para longs | 0-10% | 0% |535 | `margin_long_resistance` | Margen de resistencia para longs | 0-10% | 0.3% |536 | `margin_short_support` | Margen de soporte para shorts | 0-10% | 0.3% |537 | `margin_short_resistance` | Margen de resistencia para shorts | 0-10% | 0% |538 539 ### Lógica540 1. Detecta patrones de envolvente (high > last_high AND low < last_low)541 2. Cuenta rupturas consecutivas de S/R542 3. Cambia tendencia solo cuando se alcanza la sensibilidad configurada543 4. Actualiza niveles según la tendencia activa544 545 ---546 547 ## 💰 Gestión de Capital548 549 ### Tamaño de Posición550 El tamaño de cada posición se calcula basándose en:551 - Capital actual552 - Porcentaje de riesgo por trade553 - Distancia al stop loss554 555 ```556 risk_amount = capital × (risk_percent / 100)557 position_size = risk_amount / |entry_price - stop_loss|558 ```559 560 ### Trailing Stop561 - **LONG**: El stop loss se mueve hacia arriba cuando el soporte sube562 - **SHORT**: El stop loss se mueve hacia abajo cuando la resistencia baja563 564 ---565 566 ## 📊 Métricas Calculadas567 568 | Métrica | Descripción |569 |---------|-------------|570 | **Retorno Total** | Ganancia/pérdida absoluta y porcentual |571 | **Win Rate** | Porcentaje de trades ganadores |572 | **Profit Factor** | Ganancias brutas / Pérdidas brutas |573 | **Max Drawdown** | Máxima caída desde un pico de equity |574 | **Sharpe Ratio** | Retorno ajustado por volatilidad (anualizado) |575 | **Avg Bars Held** | Duración promedio de trades |576 577 ---578 579 ## 📈 Activos Soportados580 581 La aplicación permite analizar una amplia gama de instrumentos financieros. A continuación se detallan los activos recomendados y disponibles:582 583 #### 💻 Acciones Tech584 `AAPL`, `MSFT`, `GOOGL`, `AMZN`, `META`, `NVDA`, `TSLA`, `AMD`, `INTC`, `CRM`, `ADBE`, `NFLX`, `ORCL`, `CSCO`585 586 #### 🔗 Acciones Crypto-Related587 `MSTR`, `COIN`, `MARA`, `RIOT`, `CLSK`, `HUT`, `BITF`588 589 #### 📦 ETFs590 `SPY`, `QQQ`, `IWM`, `DIA`, `XLF`, `XLK`, `GLD`, `SLV`, `USO`, `TLT`, `VXX`, `ARKK`, `BITO`, `GBTC`591 592 > **Tip**: Puedes escribir cualquier símbolo de Yahoo Finance directamente en el selector de la pestaña de "Activo Único" para realizar el backtesting.593 594 ---595 596 ## ⚙️ Arquitectura del Sistema597 598 ```599 backtesting_app/600 ├── app.py # Aplicación principal Streamlit601 ├── algorithms/ # Módulo de algoritmos (inmutables)602 │ ├── base.py # Clase base abstracta603 │ ├── fast_ariascampos.py # Algoritmo FAST604 │ └── slow_ariascampos.py # Algoritmo SLOW605 ├── core/ # Módulo core606 │ ├── data_loader.py # Descarga de datos (yfinance)607 │ └── backtester.py # Motor de backtesting608 └── ui/ # Módulo de interfaz609 ├── visualization.py # Gráficos (Plotly)610 ├── components.py # Componentes reutilizables611 ├── single_asset.py # Tab activo único612 └── multi_asset.py # Tab multi-activo613 ```614 ---615 616 ## 📂 Estructura del Proyecto617 618 - Los algoritmos originales están protegidos en el módulo `algorithms/`619 - Solo los parámetros configurables pueden ser modificados desde la UI620 - Los datos se obtienen de **Yahoo Finance** (gratis, sin API key)621 - No se almacena información sensible622 623 ---624 625 ## 📝 Changelog626 627 ### v2.1 - Optimizaciones de Datos628 - Consolidación del motor de datos usando **yfinance**.629 - Sistema de validación de datos mejorado con detección de errores OHLCV.630 - Soporte absoluto de importaciones para mayor robustez.631 632 ### v2.0 - Arquitectura Modular633 - Separación en módulos: algorithms, core, ui634 - Soporte para múltiples algoritmos (FAST y SLOW)635 - Tab de multi-activos y Screener avanzado636 - Mejoras en visualización estilo TradingView637 638 ### v1.0 - Versión Inicial639 - Implementación de AriasCampos 5.2640 - Backtesting de activo único641 - Visualización básica642 """)643 644# =============================================================================645# FOOTER646# =============================================================================647 648st.markdown("""649<div class="footer">650 <p>AriasCampos Backtester v2.0 | Desarrollado con ❤️ usando Streamlit, Plotly y yfinance</p>651</div>652""", unsafe_allow_html=True)653 