Spaces:
Sleeping
Sleeping
| 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") | |