diegobeyl/backtesting
2
1#!/usr/bin/env python32"""3Test del algoritmo SLOW AriasCampos - Verificar cálculo correcto de soportes4Valida que:51. Las resistencias se calculen correctamente62. Cuando se rompe una resistencia en tendencia alcista, el soporte = mínimo absoluto 7 desde la creación de la resistencia hasta la vela que la rompe8"""9 10import sys11from pathlib import Path12sys.path.insert(0, str(Path(__file__).parent))13 14import pandas as pd15import numpy as np16from datetime import datetime, timedelta17from backtesting_app.algorithms.slow_ariascampos import SlowAriasCampos18 19 20def create_test_dataframe():21 """22 Crea un DataFrame de prueba que simula:23 1. Tendencia alcista inicial con soporte24 2. Se forma una resistencia cuando el precio cae25 3. Se rompe la resistencia hacia arriba26 4. El nuevo soporte debe ser el mínimo desde que se creó la resistencia27 """28 dates = pd.date_range('2024-01-01', periods=30, freq='D')29 30 # Crear datos con patrón específico para probar la lógica31 data = {32 'open': [100, 101, 102, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103],33 'high': [101, 102, 103, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104],34 'low': [99, 100, 101, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102],35 'close': [100, 101, 102, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103],36 'volume': [1000] * 3037 }38 39 df = pd.DataFrame(data, index=dates)40 return df41 42 43def test_support_calculation():44 """Test que verifica el cálculo correcto de soportes"""45 print("\n" + "="*60)46 print("TEST: Cálculo de Soporte al Romper Resistencia")47 print("="*60)48 49 algo = SlowAriasCampos()50 df = create_test_dataframe()51 52 params = algo.get_default_params()53 params['sensibilidad'] = 1 # Sin sensibilidad para prueba54 params['offset'] = 0.0 # Sin offset para números limpios55 params['support_margin_long'] = 0 # Sin margen56 params['resistance_margin_short'] = 0 # Sin margen57 58 result = algo.run(df, params)59 60 print("\nResultados por barra:")61 print(f"{'Bar':>3} {'Date':<12} {'High':>6} {'Low':>6} {'Trend':>7} {'Soporte':>8} {'Resistencia':>12}")62 print("-" * 70)63 64 for i, state in enumerate(result.states):65 trend_str = "ALCISTA" if state.trend.value == 1 else "BAJISTA" if state.trend.value == 0 else "NEUTRAL"66 support_str = f"{state.support:.2f}" if state.support else "None"67 resistance_str = f"{state.resistance:.2f}" if state.resistance else "None"68 69 high = df.iloc[i]['high']70 low = df.iloc[i]['low']71 72 print(f"{i:3d} {state.timestamp.strftime('%Y-%m-%d')} {high:6.1f} {low:6.1f} {trend_str:>7} {support_str:>8} {resistance_str:>12}")73 74 print("\n" + "="*60)75 print("Señales Generadas:")76 print("="*60)77 for signal in result.signals:78 print(f"{signal.timestamp}: {signal.signal_type} @ {signal.price:.2f} - {signal.reason}")79 80 # Validación81 print("\n" + "="*60)82 print("VALIDACIONES:")83 print("="*60)84 85 # Buscar cambios de tendencia86 changes = []87 for i in range(1, len(result.trend_history)):88 if result.trend_history[i] != result.trend_history[i-1]:89 changes.append((i, result.trend_history[i-1], result.trend_history[i]))90 91 print(f"✓ Cambios de tendencia detectados: {len(changes)}")92 for bar, from_trend, to_trend in changes:93 from_str = "ALCISTA" if from_trend.value == 1 else "BAJISTA"94 to_str = "ALCISTA" if to_trend.value == 1 else "BAJISTA"95 print(f" Barra {bar}: {from_str} → {to_str}")96 97 return result98 99 100def test_specific_scenario():101 """102 Test específico del scenario reportado:103 - Tendencia alcista con soporte104 - Se forma resistencia cuando precio cae105 - Se rompe resistencia hacia arriba106 - El nuevo soporte debe ser el mínimo desde la creación de la resistencia107 """108 print("\n" + "="*60)109 print("TEST ESPECÍFICO: Soporte en Ruptura de Resistencia")110 print("="*60)111 112 # Datos controlados para prueba específica113 dates = pd.date_range('2024-01-01', periods=20, freq='D')114 115 data = {116 'open': [100, 101, 102, 103, 104, 103, 102, 101, 100, 99, 98, 97, 96, 97, 98, 99, 100, 101, 102, 103],117 'high': [101, 102, 103, 104, 105, 104, 103, 102, 101, 100, 99, 98, 97, 98, 99, 100, 101, 102, 103, 104],118 'low': [99, 100, 101, 102, 103, 102, 101, 100, 99, 98, 97, 96, 95, 96, 97, 98, 99, 100, 101, 102],119 'close': [100, 101, 102, 103, 104, 103, 102, 101, 100, 99, 98, 97, 96, 97, 98, 99, 100, 101, 102, 103],120 'volume': [1000] * 20121 }122 123 df = pd.DataFrame(data, index=dates)124 125 algo = SlowAriasCampos()126 params = algo.get_default_params()127 params['sensibilidad'] = 1128 params['offset'] = 0.0129 params['support_margin_long'] = 0130 params['resistance_margin_short'] = 0131 132 result = algo.run(df, params)133 134 print("\nSecuencia de eventos:")135 print(f"{'Bar':>3} {'Fecha':<12} {'H':>5} {'L':>5} {'Tendencia':>8} {'Soporte':>8} {'Resistencia':>12} {'Evento':<30}")136 print("-" * 90)137 138 for i, state in enumerate(result.states):139 trend_str = "ALCISTA" if state.trend.value == 1 else "BAJISTA" if state.trend.value == 0 else "NEUTRAL"140 support_str = f"{state.support:.1f}" if state.support else "----"141 resistance_str = f"{state.resistance:.1f}" if state.resistance else "----"142 143 high = df.iloc[i]['high']144 low = df.iloc[i]['low']145 146 evento = ""147 if state.signal:148 evento = f"→ {state.signal.signal_type}"149 150 print(f"{i:3d} {state.timestamp.strftime('%Y-%m-%d')} {high:5.0f} {low:5.0f} {trend_str:>8} {support_str:>8} {resistance_str:>12} {evento:<30}")151 152 # Análisis153 print("\n" + "="*60)154 print("ANÁLISIS DEL COMPORTAMIENTO:")155 print("="*60)156 157 # Encontrar cuándo se forma la resistencia158 resistance_bar = None159 for i, val in enumerate(result.resistance_history):160 if val is not None and (resistance_bar is None or result.resistance_history[resistance_bar] is None):161 resistance_bar = i162 print(f"✓ Resistencia formada en barra {i} (valor: {val:.2f})")163 164 # Encontrar cuándo se rompe165 breakout_bar = None166 if resistance_bar is not None:167 for i in range(resistance_bar + 1, len(result.resistance_history)):168 if result.resistance_history[i] is None and result.trend_history[i].value == 1:169 breakout_bar = i170 print(f"✓ Resistencia rota en barra {i}")171 break172 173 # Verificar soporte calculado174 if breakout_bar is not None and breakout_bar + 1 < len(result.support_history):175 new_support = result.support_history[breakout_bar + 1]176 print(f"✓ Nuevo soporte establecido: {new_support:.2f}")177 178 # Calcular el mínimo esperado usando iloc en lugar de loc179 min_expected = df.iloc[resistance_bar:breakout_bar+1]['low'].min()180 print(f"✓ Mínimo en el rango [{resistance_bar}, {breakout_bar}]: {min_expected:.2f}")181 182 if abs(new_support - min_expected) < 0.1:183 print("✓✓✓ CORRECTO: El soporte coincide con el mínimo esperado")184 else:185 print(f"✗✗✗ ERROR: El soporte ({new_support:.2f}) no coincide con el mínimo ({min_expected:.2f})")186 187 188if __name__ == "__main__":189 print("\n" + "="*60)190 print("TESTS DEL ALGORITMO SLOW - ARIASCAMPOS")191 print("="*60)192 193 test_support_calculation()194 test_specific_scenario()195 196 print("\n" + "="*60)197 print("TESTS COMPLETADOS")198 print("="*60 + "\n")199 