options / app.py
Quant0's picture
Update app.py
1c11bca verified
Raw History Blame Contribute Delete
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)