Download app.py from Quant0/options: direct link, hf CLI and curl.
- Browser
- Download file 12.4 kB
-
https://huggingface.co/spaces/Quant0/options/resolve/main/app.py
- Command line
-
hf download hf://spaces/Quant0/options/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Quant0/options/resolve/main/app.py
12.4 kB
| # @title Web interactiva | |
| import gradio as gr | |
| import pandas as pd | |
| import yfinance as yf | |
| import matplotlib.pyplot as plt | |
| import plotly.graph_objects as go | |
| import numpy as np | |
| import os | |
| from datetime import date | |
| from processes import * | |
| # Función para obtener los datos y mostrarlos en el DataFrame de la UI | |
| import pandas as pd | |
| import yfinance as yf | |
| from datetime import date | |
| def generar_tabla(option_type, ticker_input, expiration_date, size_of_the_window): | |
| # Verificar si el ticker tiene opciones | |
| if not yf.Ticker(ticker_input).options: | |
| return pd.DataFrame() | |
| fechas_disponibles = pd.Series(yf.Ticker(ticker_input).options) | |
| all_tables = [] | |
| # Caso 1: expiración nula o vacía, buscar la más cercana | |
| if expiration_date is None or expiration_date == "": | |
| fecha_cercana = date.today().strftime('%Y-%m-%d') | |
| timedeltas = fechas_disponibles.apply(lambda x: pd.to_datetime(x) - pd.to_datetime(fecha_cercana)) | |
| expiration_date1 = fechas_disponibles[timedeltas.abs().idxmin()] | |
| df_final = data_option(ticker_input, expiration_date1, option_type, size_of_the_window) | |
| return df_final | |
| # Caso 2: todas las expiraciones | |
| elif expiration_date == "All": | |
| for fecha in fechas_disponibles: | |
| table = data_option(ticker_input, fecha, option_type, size_of_the_window) | |
| if not table.empty: | |
| table['dates'] = fecha | |
| all_tables.append(table) | |
| df_final = pd.concat(all_tables, ignore_index=True) | |
| return df_final | |
| # Caso 3: expiración específica | |
| else: | |
| timedeltas = fechas_disponibles.apply(lambda x: pd.to_datetime(x) - pd.to_datetime(expiration_date)) | |
| expiration_date1 = fechas_disponibles[timedeltas.abs().idxmin()] | |
| df_final = data_option(ticker_input, expiration_date1, option_type, size_of_the_window) | |
| return df_final | |
| def parse_opciones_table(df): | |
| """ | |
| Limpia y convierte un DataFrame extraído de una tabla decorada de opciones. | |
| Filtra filas válidas, convierte tipos y normaliza valores booleanos. | |
| """ | |
| # Filtrar filas que contienen símbolos válidos de opciones (ej. GOOGL251219P00165000) | |
| df_clean = df[df['contractSymbol'].str.contains(r'^[A-Z]{4,6}\d{6}[PC]\d{8}$', regex=True)].copy() | |
| # Convertir columnas relevantes a tipos numéricos | |
| df_clean['strike'] = pd.to_numeric(df_clean['strike'], errors='coerce') | |
| df_clean['volume'] = pd.to_numeric(df_clean['volume'], errors='coerce') | |
| df_clean['lastPrice'] = pd.to_numeric(df_clean['lastPrice'], errors='coerce') | |
| df_clean['impliedVolatility'] = df_clean['impliedVolatility'].astype(str).str.replace('%', '').astype(float) / 100 | |
| # Normalizar columna inTheMoney | |
| #df_clean['inTheMoney'] = df_clean['inTheMoney'].astype(str).str.upper().map({'VERDADERO': True, 'FALSO': False}) | |
| # Eliminar filas con valores nulos en columnas clave | |
| df_clean = df_clean.dropna(subset=['strike', 'volume', 'lastPrice', 'impliedVolatility']) | |
| return df_clean | |
| def plot_opciones(df_put, df_call, ticker_input, expiration_date): | |
| spot_price = yf.Ticker(ticker_input).info['regularMarketPrice'] | |
| puts_itm = df_put[df_put['strike'] > spot_price] | |
| puts_otm = df_put[df_put['strike'] <= spot_price] | |
| calls_itm = df_call[df_call['strike'] < spot_price] | |
| calls_otm = df_call[df_call['strike'] >= spot_price] | |
| fig1 = go.Figure() | |
| fig1.add_trace(go.Bar(x=puts_itm['strike'], y=puts_itm['volume'], name='PUT ITM', marker_color='green', width=1)) | |
| fig1.add_trace(go.Bar(x=puts_otm['strike'], y=puts_otm['volume'], name='PUT OTM', marker_color='red',width=1)) | |
| fig1.add_trace(go.Bar(x=calls_itm['strike'], y=calls_itm['volume'], name='CALL ITM', marker_color='blue',width=1)) | |
| fig1.add_trace(go.Bar(x=calls_otm['strike'], y=calls_otm['volume'], name='CALL OTM', marker_color='orange',width=1)) | |
| fig1.add_trace(go.Scatter(x=[spot_price], y=[0], mode='markers+text', | |
| marker=dict(color='black', size=10), | |
| text=[f'Spot: {spot_price}'], | |
| textposition='top center', | |
| name='Spot Price')) | |
| # Agrega la línea vertical discontinua | |
| fig1.add_trace(go.Scatter( | |
| x=[spot_price, spot_price], | |
| y=[0, max(max(puts_itm['volume']), max(puts_otm['volume']), max(calls_itm['volume']), max(calls_otm['volume'])) * 1.1], | |
| mode='lines', | |
| name=f'Spot: {spot_price}', | |
| marker=dict(color='black', size=10), | |
| line=dict(dash='dash'), | |
| showlegend=False | |
| )) | |
| fig1.update_layout(title=f"Didtribución del Volumen {ticker_input}", | |
| xaxis_title='Strike', | |
| yaxis_title='Volumen', | |
| barmode='stack', | |
| template='plotly_white', | |
| legend=dict( | |
| orientation="h", | |
| yanchor="top", | |
| y=-0.2, | |
| xanchor="center", | |
| x=0.5) | |
| ) | |
| fig2 = go.Figure() | |
| fig2.add_trace(go.Scatter( | |
| x=df_put['strike'], | |
| y=df_put['impliedVolatility'], | |
| mode='markers+lines', | |
| name='PUT', | |
| marker=dict(color='red') | |
| )) | |
| fig2.add_trace(go.Scatter( | |
| x=df_call['strike'], | |
| y=df_call['impliedVolatility'], | |
| mode='markers+lines', | |
| name='CALL', | |
| marker=dict(color='blue') | |
| )) | |
| # Agrega la línea vertical aquí | |
| fig2.add_vline(x=spot_price, line_width=2, line_dash="dot", line_color="black") | |
| fig2.update_layout( | |
| title=f"Volatilidad Implícita por Strike {ticker_input}", | |
| xaxis_title='Strike', | |
| yaxis_title='Volatilidad Implícita', | |
| template='plotly_white', | |
| legend=dict( | |
| orientation="h", | |
| yanchor="top", | |
| y=-0.2, | |
| xanchor="center", | |
| x=0.5) | |
| ) | |
| return fig1, fig2 | |
| def generar_puts(ticker_input, expiration_date, size_of_the_window): | |
| ticker_input = ticker_input | |
| puts = generar_tabla("put", ticker_input, expiration_date, size_of_the_window) | |
| clean_puts = parse_opciones_table(puts) | |
| return puts, clean_puts | |
| def generar_calls(ticker_input, expiration_date, size_of_the_window): | |
| ticker_input = ticker_input | |
| calls = generar_tabla("call", ticker_input, expiration_date, size_of_the_window) | |
| clean_calls = parse_opciones_table(calls) | |
| return calls, clean_calls | |
| def generar_todo(ticker_input, expiration_date, size_of_the_window): | |
| puts = generar_puts(ticker_input, expiration_date, size_of_the_window)[0] | |
| puts_clean = generar_puts(ticker_input, expiration_date, size_of_the_window)[1] | |
| calls = generar_calls(ticker_input, expiration_date, size_of_the_window)[0] | |
| calls_clean = generar_calls(ticker_input, expiration_date, size_of_the_window)[1] | |
| return puts, puts_clean, calls, calls_clean | |
| # Función para generar y devolver el archivo Excel | |
| def exportar_a_excel(option_type, ticker_input, expiration_date, size_of_the_window): | |
| df_final = generar_tabla(option_type, ticker_input, expiration_date, size_of_the_window) | |
| try: | |
| if not df_final.empty: | |
| nombre_archivo = f"{ticker_input}_opciones_{option_type}.xlsx" | |
| df_final.to_excel(nombre_archivo, index=False) | |
| return nombre_archivo, "Archivo Excel generado con éxito." | |
| else: | |
| return None, "No se pudieron generar los datos para exportar." | |
| except Exception as e: | |
| return None, f"Error al exportar: {e}" | |
| def exportar_a_excel_con_hojas(ticker_input, expiration_date, size_of_the_window): | |
| df_puts = generar_puts(ticker_input, expiration_date, size_of_the_window)[0] | |
| df_calls = generar_calls(ticker_input, expiration_date, size_of_the_window)[0] | |
| ticker = ticker_input.upper() | |
| nombre_archivo = f"{ticker}_opciones.xlsx" | |
| try: | |
| with pd.ExcelWriter(nombre_archivo) as writer: | |
| # Escribe el DataFrame de 'puts' en la primera hoja | |
| if not df_puts.empty: | |
| df_puts.to_excel(writer, sheet_name='Puts', index=False) | |
| # Escribe el DataFrame de 'calls' en la segunda hoja | |
| if not df_calls.empty: | |
| df_calls.to_excel(writer, sheet_name='Calls', index=False) | |
| return nombre_archivo, "Archivo Excel generado con éxito." | |
| except Exception as e: | |
| return None, f"Error al exportar: {e}" | |
| # ------------------------------- | |
| # Configuración de Gradio | |
| # ------------------------------- | |
| # --- Valores por defecto para inicializar la tabla --- | |
| initial_df_put = generar_tabla("put", "MSTR", '', 16) | |
| initial_df_call = generar_tabla("call", "MSTR", '', 16) | |
| with gr.Blocks(title="Análisis de Opciones") as demo: | |
| df_put_state = gr.State(value=parse_opciones_table(initial_df_put)) | |
| df_call_state = gr.State(value=parse_opciones_table(initial_df_call)) | |
| # Añade esta línea con la URL de tu imagen | |
| gr.Image("https://cdn.prod.website-files.com/67174dcb1d43b06a0eae317e/672bbbc7a2b88045e5661994_logo-afi.svg", show_label=False) | |
| gr.Markdown("# Analizador de Opciones") | |
| gr.Markdown("#### Herramienta para visualizar y exportar datos de opciones.") | |
| gr.Markdown("Introduzca el tipo de opción que desea consultar, indicando el Ticker y la Fecha de vencimiento. Si no se especifica una fecha de vencimiento, se mostrarán todas las disponibles.") | |
| with gr.Row(): | |
| ticker_input = gr.Textbox(label="Ticker (ej. GOOGL)", value="MSTR") | |
| expiration_date = gr.Textbox(label="Fecha de vencimiento (formato: aaaa-mm-dd)", value = "" ) | |
| size_of_the_window = gr.Slider(minimum=1, maximum=30, value=16, step=1, label="Tamaño de la ventana") | |
| btn_mostrar = gr.Button('Cargar Datos') | |
| with gr.Tab("Puts"): | |
| with gr.Row(): | |
| gr.Markdown("# Opciones Put") | |
| with gr.Row(): | |
| output_df_put = gr.DataFrame(label="Datos de Opciones put", value=initial_df_put) | |
| ''' | |
| ticker_input.change( | |
| fn = generar_puts, | |
| inputs=[ticker_input, expiration_date, size_of_the_window], | |
| outputs= [ output_df_put, df_put_state] | |
| ) | |
| ''' | |
| with gr.Tab("Calls"): | |
| with gr.Row(): | |
| gr.Markdown("# Opciones Call") | |
| #btn_mostrar2 = gr.Button("Mostrar datos") | |
| with gr.Row(): | |
| output_df_call = gr.DataFrame(label="Datos de Opciones call", value=initial_df_call) | |
| ''' | |
| ticker_input.change( | |
| fn = generar_calls, | |
| inputs=[ticker_input, expiration_date, size_of_the_window], | |
| outputs= [ output_df_call, df_call_state] | |
| ) | |
| ''' | |
| with gr.Tab("Plots"): | |
| btn_plot = gr.Button("Mostrar Plot") | |
| with gr.Row(): | |
| output_plot1 = gr.Plot(label="Distribución de Volumen de las opciones") | |
| output_plot2 = gr.Plot(label = 'Volatilidad Implícita por strike') | |
| btn_plot.click( | |
| fn=plot_opciones, | |
| inputs=[df_put_state, df_call_state, ticker_input, expiration_date], | |
| outputs=[output_plot1, output_plot2] | |
| ) | |
| with gr.Tab("Exportar"): | |
| gr.Markdown("# Exportación:") | |
| gr.Markdown("### Se generará un archivo excel con dos hojas: Calls y Puts, con las correspondientes tablas según los datos seleccionados") | |
| btn_descargar = gr.Button("Descargar en Excel") | |
| output_file = gr.File(label="Archivo Excel") | |
| output_msg = gr.Label() | |
| # Enlaza el botón "Mostrar datos" para actualizar los dataframes y luego para graficar. | |
| btn_descargar.click( | |
| fn=exportar_a_excel_con_hojas, | |
| inputs=[ticker_input, expiration_date, size_of_the_window], | |
| outputs=[output_file, output_msg] | |
| ) | |
| btn_mostrar.click( | |
| fn=generar_todo, | |
| inputs=[ticker_input, expiration_date, size_of_the_window], | |
| outputs= [ output_df_put, df_put_state, output_df_call, df_call_state] | |
| ) | |
| # Inicia la aplicación | |
| demo.launch(share=True) |