import dash from dash import dcc, html from dash.dependencies import Input, Output, State import pandas as pd import plotly.graph_objects as go import numpy as np from datetime import datetime, timedelta # --- 1. Generación de Datos Simulados (Mock Data) --- def generar_datos_precios(dias=30): """Genera un DataFrame simulado de precios diarios.""" # Crear un rango de fechas fechas = [datetime.now() - timedelta(days=i) for i in range(dias)][::-1] # Simular una trayectoria de precios (ejemplo: un paseo aleatorio) # Empezamos en 100 y añadimos ruido precios = [100.0] for _ in range(dias - 1): # El cambio es un número aleatorio pequeño (-1 a 1) cambio = np.random.uniform(-1, 1) * 0.5 nuevo_precio = precios[-1] + cambio # Nos aseguramos de que el precio no baje de 90 precios.append(max(90, nuevo_precio)) df = pd.DataFrame({ 'Fecha': fechas, 'Precio': [float(f'{p:.2f}') for p in precios] # Formato a 2 decimales }) return df df_precios = generar_datos_precios() precio_actual = df_precios['Precio'].iloc[-1] # --- 2. Inicialización de la Aplicación Dash --- app = dash.Dash(__name__) # --- 3. Diseño (Layout) de la Aplicación --- app.layout = html.Div(style={'backgroundColor': '#1f2630', 'color': '#c7d0d9', 'padding': '20px'}, children=[ html.H1("Simulador de Trading con Dash/Plotly", style={'textAlign': 'center', 'color': '#00bcd4'}), html.P(f"Precio Actual del Activo (CEJ): ${precio_actual:.2f}", id='precio-actual-display', style={'textAlign': 'center', 'fontSize': '1.5em'}), # Gráfico interactivo (Candlestick o Línea) dcc.Graph(id='grafico-precios', style={'height': '60vh'}), html.Div([ dcc.Input(id='input-cantidad', type='number', value=1, min=1, style={'marginRight': '10px', 'padding': '10px', 'width': '100px'}), html.Button('COMPRAR ACTIVO', id='boton-comprar', n_clicks=0, style={'padding': '10px 20px', 'backgroundColor': '#4CAF50', 'color': 'white', 'border': 'none', 'borderRadius': '5px', 'cursor': 'pointer'}), ], style={'textAlign': 'center', 'marginTop': '20px'}), html.Div(id='output-transaccion', style={'textAlign': 'center', 'marginTop': '15px', 'fontSize': '1.2em', 'minHeight': '30px'}) ]) # --- 4. Callbacks para la Interactividad --- # Callback para actualizar el gráfico @app.callback( Output('grafico-precios', 'figure'), [Input('grafico-precios', 'relayoutData')] # Esto es solo para que Dash sepa cuándo refrescar (en apps reales, usarías dcc.Interval) ) def actualizar_grafico(relayout_data): """Dibuja un gráfico de línea simple con los precios simulados.""" fig = go.Figure(data=[ go.Scatter( x=df_precios['Fecha'], y=df_precios['Precio'], mode='lines+markers', name='Precio', line={'color': '#00bcd4'} # Color del gráfico ) ]) fig.update_layout( title='Histórico de Precios del Activo (CEJ)', xaxis_title='Fecha', yaxis_title='Precio (USD)', plot_bgcolor='#273142', # Fondo del gráfico paper_bgcolor='#1f2630', # Fondo general de la figura font_color='#c7d0d9' ) return fig # Callback para manejar la compra @app.callback( [Output('output-transaccion', 'children'), Output('precio-actual-display', 'children')], [Input('boton-comprar', 'n_clicks')], [State('input-cantidad', 'value')] ) def manejar_transaccion(n_clicks, cantidad): global precio_actual # Esta función se dispara al inicio, ignoramos el primer click (n_clicks=0) if n_clicks is None or n_clicks == 0: # Esto solo asegura que el display del precio inicial sea correcto return "", f"Precio Actual del Activo (CEJ): ${precio_actual:.2f}" # Simulamos que el precio puede haber cambiado (idealmente, esto vendría de un dcc.Interval) # Para este ejemplo, solo usaremos el precio final de los datos simulados costo_total = precio_actual * cantidad mensaje = f"✅ ¡COMPRA EXITOSA! {cantidad} unidades de CEJ a ${precio_actual:.2f} cada una. Costo total: ${costo_total:.2f}" # La salida del precio actual se mantiene: precio_display = f"Precio Actual del Activo (CEJ): ${precio_actual:.2f}" return mensaje, precio_display # --- 5. Ejecución del Servidor --- if __name__ == '__main__': # El debug=True permite que los cambios en el código se reflejen automáticamente app.run_server(debug=True)