File size: 13,965 Bytes
275417a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
import streamlit as st
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io
import os
from datetime import datetime
import pandas as pd
from sklearn.linear_model import LinearRegression

# Configuración de la página
st.set_page_config(
    page_title="Análisis Técnico de Trading",
    page_icon="📈",
    layout="wide"
)

# Título y descripción
st.title("Análisis Técnico de Trading")
st.markdown("""
Esta aplicación analiza gráficos de activos financieros y proporciona recomendaciones de trading.
Sube una imagen de un gráfico y obtén un análisis técnico junto con recomendaciones a corto y largo plazo.
""")

# Función para cargar y procesar la imagen
def load_and_process_image(uploaded_file):
    if uploaded_file is not None:
        # Leer la imagen
        image = Image.open(uploaded_file)
        img_array = np.array(image)
        
        # Convertir a escala de grises para procesamiento
        gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY) if len(img_array.shape) > 2 else img_array
        
        return image, img_array, gray
    return None, None, None

# Función para detectar tendencias en el gráfico
def detect_trend(img_array, gray):
    # Detectar bordes
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    
    # Detectar líneas usando la transformada de Hough
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=100, minLineLength=100, maxLineGap=10)
    
    # Analizar pendientes de las líneas para determinar tendencia
    slopes = []
    if lines is not None:
        for line in lines:
            x1, y1, x2, y2 = line[0]
            if x2 != x1:  # Evitar división por cero
                slope = (y2 - y1) / (x2 - x1)
                slopes.append(slope)
    
    # Determinar tendencia basada en pendientes
    if not slopes:
        return "Neutral", 0
    
    avg_slope = np.mean(slopes)
    
    # En gráficos, y aumenta hacia abajo, por lo que pendiente negativa = tendencia alcista
    if avg_slope < -0.1:
        strength = min(abs(avg_slope) * 10, 10)
        return "Alcista", strength
    elif avg_slope > 0.1:
        strength = min(abs(avg_slope) * 10, 10)
        return "Bajista", strength
    else:
        return "Neutral", min(abs(avg_slope) * 20, 5)

# Función para detectar patrones de velas
def detect_candlestick_patterns(img_array):
    # Simulación de detección de patrones
    # En una implementación real, se utilizaría un modelo entrenado para reconocer patrones
    
    # Detectar colores predominantes (verde/rojo)
    hsv = cv2.cvtColor(img_array, cv2.COLOR_RGB2HSV)
    
    # Máscara para color verde (velas alcistas)
    lower_green = np.array([40, 40, 40])
    upper_green = np.array([80, 255, 255])
    green_mask = cv2.inRange(hsv, lower_green, upper_green)
    green_count = np.sum(green_mask > 0)
    
    # Máscara para color rojo (velas bajistas)
    lower_red1 = np.array([0, 50, 50])
    upper_red1 = np.array([10, 255, 255])
    lower_red2 = np.array([170, 50, 50])
    upper_red2 = np.array([180, 255, 255])
    red_mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
    red_mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
    red_mask = red_mask1 + red_mask2
    red_count = np.sum(red_mask > 0)
    
    patterns = []
    
    # Determinar patrones basados en colores predominantes
    if green_count > red_count * 1.5:
        patterns.append("Posible patrón de velas alcistas")
        if np.random.random() > 0.5:  # Simulación
            patterns.append("Posible Martillo Alcista")
    elif red_count > green_count * 1.5:
        patterns.append("Posible patrón de velas bajistas")
        if np.random.random() > 0.5:  # Simulación
            patterns.append("Posible Estrella Fugaz")
    else:
        patterns.append("Patrón de velas mixto o indeciso")
        if np.random.random() > 0.7:  # Simulación
            patterns.append("Posible Doji")
    
    return patterns

# Función para detectar soportes y resistencias
def detect_support_resistance(gray):
    # Simulación de detección de soportes y resistencias
    # En una implementación real, se utilizaría análisis de histograma o detección de líneas horizontales
    
    # Proyección horizontal (suma de píxeles por fila)
    h_projection = np.sum(gray, axis=1)
    
    # Normalizar
    h_projection = h_projection / np.max(h_projection)
    
    # Encontrar picos (posibles soportes/resistencias)
    peaks = []
    for i in range(1, len(h_projection) - 1):
        if h_projection[i] > h_projection[i-1] and h_projection[i] > h_projection[i+1] and h_projection[i] > 0.7:
            peaks.append((i, h_projection[i]))
    
    # Ordenar por intensidad
    peaks.sort(key=lambda x: x[1], reverse=True)
    
    # Tomar los 3 picos más fuertes
    top_peaks = peaks[:min(3, len(peaks))]
    
    # Convertir a niveles de soporte/resistencia
    levels = []
    height = gray.shape[0]
    
    for peak in top_peaks:
        y_pos = peak[0]
        # En gráficos, la parte superior es resistencia, la parte inferior es soporte
        if y_pos < height / 2:
            levels.append(("Resistencia", y_pos / height))
        else:
            levels.append(("Soporte", y_pos / height))
    
    return levels

# Función para generar recomendaciones
def generate_recommendations(trend, trend_strength, patterns, support_resistance):
    recommendations = {
        "corto_plazo": "",
        "largo_plazo": "",
        "niveles_clave": [],
        "confianza_corto": 0,
        "confianza_largo": 0
    }
    
    # Recomendación a corto plazo basada en tendencia y patrones
    if trend == "Alcista":
        if trend_strength > 7:
            recommendations["corto_plazo"] = "Comprar con stop loss ajustado"
            recommendations["confianza_corto"] = min(trend_strength * 0.9, 9)
        elif trend_strength > 4:
            recommendations["corto_plazo"] = "Comprar en retrocesos"
            recommendations["confianza_corto"] = trend_strength * 0.8
        else:
            recommendations["corto_plazo"] = "Comprar con precaución"
            recommendations["confianza_corto"] = trend_strength * 0.7
            
    elif trend == "Bajista":
        if trend_strength > 7:
            recommendations["corto_plazo"] = "Vender o abrir cortos"
            recommendations["confianza_corto"] = min(trend_strength * 0.9, 9)
        elif trend_strength > 4:
            recommendations["corto_plazo"] = "Vender rebotes"
            recommendations["confianza_corto"] = trend_strength * 0.8
        else:
            recommendations["corto_plazo"] = "Mantener posiciones cortas existentes"
            recommendations["confianza_corto"] = trend_strength * 0.7
    else:
        recommendations["corto_plazo"] = "Mantenerse al margen, mercado sin dirección clara"
        recommendations["confianza_corto"] = trend_strength * 0.5
    
    # Ajustar recomendación basada en patrones de velas
    for pattern in patterns:
        if "alcista" in pattern.lower() and trend != "Bajista":
            recommendations["corto_plazo"] += ". " + pattern + " refuerza señal de compra"
            recommendations["confianza_corto"] = min(recommendations["confianza_corto"] + 1, 10)
        elif "bajista" in pattern.lower() and trend != "Alcista":
            recommendations["corto_plazo"] += ". " + pattern + " refuerza señal de venta"
            recommendations["confianza_corto"] = min(recommendations["confianza_corto"] + 1, 10)
        elif "doji" in pattern.lower():
            recommendations["corto_plazo"] += ". " + pattern + " indica indecisión, considerar reducir exposición"
            recommendations["confianza_corto"] = max(recommendations["confianza_corto"] - 1, 1)
    
    # Recomendación a largo plazo
    if trend == "Alcista":
        recommendations["largo_plazo"] = "Mantener posiciones largas con visión de medio/largo plazo"
        recommendations["confianza_largo"] = min(trend_strength * 0.7, 8)
    elif trend == "Bajista":
        recommendations["largo_plazo"] = "Considerar estrategias de cobertura para el largo plazo"
        recommendations["confianza_largo"] = min(trend_strength * 0.7, 8)
    else:
        recommendations["largo_plazo"] = "Acumular gradualmente en niveles de soporte clave"
        recommendations["confianza_largo"] = 5
    
    # Añadir información de soportes y resistencias
    for level_type, level_value in support_resistance:
        if level_type == "Soporte":
            recommendations["niveles_clave"].append(f"Soporte en nivel {level_value:.2f}")
            if trend == "Alcista":
                recommendations["largo_plazo"] += f". Considerar aumentar posición en soporte {level_value:.2f}"
        else:  # Resistencia
            recommendations["niveles_clave"].append(f"Resistencia en nivel {level_value:.2f}")
            if trend == "Bajista":
                recommendations["largo_plazo"] += f". Considerar reducir exposición en resistencia {level_value:.2f}"
    
    return recommendations

# Función para visualizar el análisis
def visualize_analysis(image, trend, patterns, support_resistance):
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.imshow(image)
    
    # Añadir anotaciones
    height, width = image.size[1], image.size[0]
    
    # Anotar tendencia
    ax.text(width * 0.05, height * 0.1, f"Tendencia: {trend}", 
            color='white', fontsize=12, bbox=dict(facecolor='black', alpha=0.7))
    
    # Anotar patrones
    for i, pattern in enumerate(patterns):
        ax.text(width * 0.05, height * (0.2 + i * 0.05), pattern, 
                color='white', fontsize=10, bbox=dict(facecolor='blue', alpha=0.7))
    
    # Anotar soportes y resistencias
    for level_type, level_value in support_resistance:
        y_pos = int(level_value * height)
        color = 'green' if level_type == "Soporte" else 'red'
        ax.axhline(y=y_pos, color=color, linestyle='--', alpha=0.7)
        ax.text(width * 0.8, y_pos, level_type, 
                color='white', fontsize=10, bbox=dict(facecolor=color, alpha=0.7))
    
    plt.axis('off')
    return fig

# Interfaz principal
uploaded_file = st.file_uploader("Sube una imagen de un gráfico", type=["jpg", "jpeg", "png"])

if uploaded_file is not None:
    # Mostrar imagen original
    image, img_array, gray = load_and_process_image(uploaded_file)
    
    if image is not None:
        st.image(image, caption="Gráfico subido", use_column_width=True)
        
        with st.spinner('Analizando gráfico...'):
            # Detectar tendencia
            trend, trend_strength = detect_trend(img_array, gray)
            
            # Detectar patrones de velas
            patterns = detect_candlestick_patterns(img_array)
            
            # Detectar soportes y resistencias
            support_resistance = detect_support_resistance(gray)
            
            # Generar recomendaciones
            recommendations = generate_recommendations(trend, trend_strength, patterns, support_resistance)
            
            # Mostrar análisis
            st.subheader("Análisis Técnico")
            
            col1, col2 = st.columns(2)
            
            with col1:
                st.markdown(f"**Tendencia detectada:** {trend}")
                st.markdown(f"**Fuerza de la tendencia:** {trend_strength:.1f}/10")
                
                st.markdown("**Patrones identificados:**")
                for pattern in patterns:
                    st.markdown(f"- {pattern}")
                
                st.markdown("**Niveles clave:**")
                for level in recommendations["niveles_clave"]:
                    st.markdown(f"- {level}")
            
            with col2:
                # Visualizar análisis
                fig = visualize_analysis(image, trend, patterns, support_resistance)
                st.pyplot(fig)
            
            # Mostrar recomendaciones
            st.subheader("Recomendaciones de Trading")
            
            rec_col1, rec_col2 = st.columns(2)
            
            with rec_col1:
                st.markdown("### Operación a Corto Plazo")
                st.markdown(recommendations["corto_plazo"])
                st.progress(float(recommendations["confianza_corto"]/10))
                st.markdown(f"*Nivel de confianza: {recommendations['confianza_corto']:.1f}/10*")
            
            with rec_col2:
                st.markdown("### Estrategia a Largo Plazo")
                st.markdown(recommendations["largo_plazo"])
                st.progress(float(recommendations["confianza_largo"]/10))
                st.markdown(f"*Nivel de confianza: {recommendations['confianza_largo']:.1f}/10*")
            
            # Disclaimer
            st.markdown("---")
            st.markdown("""
            **Disclaimer:** Este análisis es generado automáticamente y tiene fines educativos. 
            No constituye asesoramiento financiero. Realice su propia investigación antes de tomar decisiones de inversión.
            """)
else:
    # Mostrar ejemplo cuando no hay archivo subido
    st.info("👆 Sube una imagen de un gráfico para comenzar el análisis")
    
    # Mostrar información de ejemplo
    st.subheader("¿Cómo funciona?")
    st.markdown("""
    1. **Sube una imagen** de un gráfico de cualquier activo financiero
    2. La aplicación **analiza automáticamente** la tendencia, patrones y niveles clave
    3. Recibe **recomendaciones de trading** a corto y largo plazo
    
    La aplicación utiliza técnicas de procesamiento de imágenes y análisis técnico para identificar:
    - Tendencias alcistas, bajistas o laterales
    - Patrones de velas japonesas
    - Niveles de soporte y resistencia
    - Señales de compra o venta
    """)

# Información del pie de página
st.markdown("---")
st.markdown("Desarrollado con ❤️ usando Streamlit y técnicas de análisis de imágenes")