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")