diegobeyl/backtesting
2
1"""
2Debug del cálculo de tamaño de posición
3Verifica por qué el P&L está 10x menor
4"""
5
6import sys
7import os
8import pandas as pd
9from datetime import datetime, timedelta
10
11# Agregar path correcto
12sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'backtesting_app', 'backtesting_app'))
13
14from core.data_loader import DataLoader
15from core.backtester import Backtester
16from algorithms.fast_ariascampos import FastAriasCampos
17
18
19def debug_backtest():
20 """Ejecuta backtest con debug detallado"""
21
22 print("=" * 80)
23 print("DEBUG: ANÁLISIS DE TAMAÑO DE POSICIÓN")
24 print("=" * 80)
25 print()
26
27 # Parámetros
28 symbol = 'AAPL'
29 timeframe = '1mo'
30 initial_capital = 10000
31 risk_percent = 1.0
32
33 # Descargar datos
34 end_date = datetime.now()
35 start_date = end_date - timedelta(days=365*10)
36
37 print(f"📊 Descargando datos de {symbol}...")
38 print(f" Timeframe: {timeframe}")
39 print(f" Período: {start_date.date()} a {end_date.date()}")
40
41 df = DataLoader.download(
42 symbol=symbol,
43 interval=timeframe,
44 start_date=start_date.strftime('%Y-%m-%d'),
45 end_date=end_date.strftime('%Y-%m-%d'),
46 source='yfinance'
47 )
48
49 if df is None or df.empty:
50 print("❌ Error: No se pudieron descargar datos")
51 return
52
53 print(f"✅ {len(df)} velas descargadas\n")
54
55 # Ejecutar backtest
56 print("=" * 80)
57 print("CONFIGURACIÓN DEL BACKTEST")
58 print("=" * 80)
59 print(f"Capital Inicial: ${initial_capital:,.2f}")
60 print(f"Riesgo por Trade: {risk_percent}%")
61 print(f"Riesgo en dólares: ${initial_capital * risk_percent / 100:,.2f}")
62 print()
63
64 algorithm = FastAriasCampos()
65 algo_params = {
66 'lookbehind': 0,
67 'stop_resets_support': True,
68 'break_margin': 0.0,
69 'timeframe': timeframe
70 }
71
72 backtester = Backtester(
73 algorithm=algorithm,
74 initial_capital=initial_capital,
75 risk_percent=risk_percent,
76 commission_pct=0.1
77 )
78
79 result = backtester.run(df, algo_params, symbol, timeframe)
80
81 # Análisis detallado de trades
82 print("=" * 80)
83 print("ANÁLISIS DETALLADO DE CADA TRADE")
84 print("=" * 80)
85 print()
86
87 for i, trade in enumerate(result.trades[:10], 1): # Primeros 10 trades
88 print(f"{'='*80}")
89 print(f"TRADE #{i} - {trade.direction}")
90 print(f"{'='*80}")
91 print(f"Fecha Entrada: {trade.entry_date}")
92 print(f"Precio Entrada: ${trade.entry_price:,.2f}")
93 print(f"Stop Loss Inicial: ${trade.initial_sl:,.2f}")
94
95 # Cálculos
96 sl_distance = abs(trade.entry_price - trade.initial_sl)
97 sl_distance_pct = (sl_distance / trade.entry_price) * 100
98
99 print(f"\n📏 DISTANCIA AL STOP:")
100 print(f" Absoluta: ${sl_distance:,.2f}")
101 print(f" Porcentual: {sl_distance_pct:.2f}%")
102
103 # Cálculo esperado de posición
104 risk_amount = trade.capital_at_entry * (risk_percent / 100)
105 expected_position_size = risk_amount / sl_distance
106
107 print(f"\n💰 CÁLCULO DE POSICIÓN:")
108 print(f" Capital disponible: ${trade.capital_at_entry:,.2f}")
109 print(f" Riesgo {risk_percent}%: ${risk_amount:,.2f}")
110 print(f" Tamaño esperado: {expected_position_size:,.2f} acciones")
111 print(f" Tamaño REAL: {trade.position_size:,.2f} acciones")
112
113 # Verificar discrepancia
114 if abs(expected_position_size - trade.position_size) > 0.1:
115 print(f" ⚠️ DISCREPANCIA: {abs(expected_position_size - trade.position_size):,.2f} acciones")
116
117 # Valor de posición
118 position_value = trade.position_size * trade.entry_price
119 leverage = position_value / trade.capital_at_entry
120
121 print(f"\n📊 VALOR DE POSICIÓN:")
122 print(f" Valor total: ${position_value:,.2f}")
123 print(f" Apalancamiento: {leverage:.2f}x")
124 print(f" % del capital: {leverage * 100:.1f}%")
125
126 # Resultado
127 if trade.exit_price:
128 print(f"\n💵 RESULTADO:")
129 print(f" Precio Salida: ${trade.exit_price:,.2f}")
130 print(f" Razón: {trade.exit_reason}")
131
132 # Cálculo manual del P&L
133 if trade.direction == 'LONG':
134 price_diff = trade.exit_price - trade.entry_price
135 else:
136 price_diff = trade.entry_price - trade.exit_price
137
138 expected_pnl = price_diff * trade.position_size
139
140 print(f"\n Diferencia de precio: ${price_diff:,.2f}")
141 print(f" P&L esperado: ${expected_pnl:,.2f}")
142 print(f" P&L REAL: ${trade.pnl:,.2f}")
143
144 if abs(expected_pnl - trade.pnl) > 10:
145 print(f" ⚠️ DISCREPANCIA EN P&L: ${abs(expected_pnl - trade.pnl):,.2f}")
146
147 print(f" P&L %: {trade.pnl_percent:+.2f}%")
148 print(f" Barras mantenidas: {trade.bars_held}")
149
150 print()
151
152 # Resumen
153 print("=" * 80)
154 print("RESUMEN GENERAL")
155 print("=" * 80)
156 print(f"Total Trades: {result.total_trades}")
157 print(f"Capital Final: ${result.total_return:,.2f}")
158 print(f"Retorno: ${result.total_return - initial_capital:,.2f}")
159 print(f"Retorno %: {result.total_return_percent:+.2f}%")
160 print(f"Win Rate: {result.win_rate:.1f}%")
161 print()
162
163 # Verificar problema específico
164 print("=" * 80)
165 print("🔍 DIAGNÓSTICO")
166 print("=" * 80)
167 print()
168
169 if result.total_trades > 0:
170 avg_position_value = sum(t.position_size * t.entry_price for t in result.trades) / len(result.trades)
171 avg_leverage = avg_position_value / initial_capital
172
173 print(f"Valor promedio de posición: ${avg_position_value:,.2f}")
174 print(f"Apalancamiento promedio: {avg_leverage:.2f}x")
175
176 if avg_leverage < 0.1:
177 print("⚠️ PROBLEMA: Posiciones muy pequeñas (< 10% del capital)")
178 print(" Esto explicaría por qué el P&L es 10x menor")
179 print()
180 print(" POSIBLES CAUSAS:")
181 print(" 1. Los stops están muy lejos del precio de entrada")
182 print(" 2. El riesgo por trade es muy bajo")
183 print(" 3. Hay un error en el cálculo de position_size")
184
185
186if __name__ == "__main__":
187 debug_backtest()
188 