File size: 12,380 Bytes
2790b9b 62c3084 2790b9b 125039f 0e29764 ac75647 2790b9b 7192bda 2790b9b 7192bda 2790b9b 7192bda 125039f 7192bda 2790b9b 7192bda 2790b9b 7192bda ac75647 d6ad76b ac75647 d6ad76b ac75647 988b44e 5d100f4 988b44e ac75647 988b44e ac75647 d83cc2c ac75647 1c11bca 988b44e 64b213e 988b44e d83cc2c 988b44e 1c11bca 988b44e ac75647 30e2471 2c180b7 eb277cc e557b9b 30e2471 e557b9b 30e2471 2790b9b 4874231 09ccdd6 4874231 2790b9b 45a7ed6 9885517 28dd066 faac560 28dd066 ea71fb1 2237549 30e2471 2237549 ea71fb1 a0c692f ea71fb1 2790b9b 125039f 2790b9b 2f3fbfc 21664cd 2f3fbfc 2790b9b 9f0dbbf 9d3eed3 25b5f4c 8c4570c 64bdd94 8c4570c 64bdd94 a69da38 28b8b73 2ccef83 9d3eed3 cbc30ae eaa4938 2ccef83 9d3eed3 8c4570c dbebf42 64bdd94 2ccef83 8c4570c 059ef7b 8c4570c 28b8b73 ce8e1b4 09ccdd6 9d3eed3 cbc30ae eaa4938 2ccef83 9d3eed3 8c4570c 4014a5c 2ed860f 8c4570c b9d448b ce8e1b4 2ed860f ce8e1b4 5fc9f9c 8c4570c a69da38 8c4570c dac23ed b7dd58c 5fc9f9c 25b5f4c 09ccdd6 474b75e 09ccdd6 ce8e1b4 2790b9b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | # @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) |