Team Ai
Apppublic

javitechjkd/backtestingv2

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
app.py653 linesDownload Raw Back to backtesting_app
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