Download app.py from Quant0/BTC: direct link, hf CLI and curl.
- Browser
- Download file 25.2 kB
-
https://huggingface.co/spaces/Quant0/BTC/resolve/main/app.py
- Command line
-
hf download hf://spaces/Quant0/BTC/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Quant0/BTC/resolve/main/app.py
25.2 kB
| # @title Texto de t铆tulo predeterminado | |
| # Instala la librer铆a gdown para descargar archivos de Google Drive | |
| # Esto solo necesita ejecutarse una vez al inicio. | |
| # Se incluye aqu铆 para que el c贸digo sea autocontenido. | |
| import plotly.graph_objects as go | |
| import gradio as gr | |
| import pandas as pd | |
| import yfinance as yf | |
| import matplotlib.pyplot as plt | |
| from datetime import datetime, timedelta | |
| import os | |
| from IPython.display import HTML | |
| import numpy as np | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import re | |
| from openpyxl.utils import get_column_letter | |
| import shutil | |
| import gdown | |
| from processes import all_historical_data | |
| from processes import data_option | |
| # Diccionarios de datos y funciones auxiliares | |
| tickers_to_ids = { | |
| "MSTR": 1, "MARA": 4, "CEP": 436, "BSTR": 674, "RIOT": 7, "DJT": 671, "3350.T": 176, "GLXY": 10, "CLSK": 28, "TSLA": 2, | |
| "HUT": 6, "COIN": 8, "XYZ": 5, "NXTT": 473, "CCCM": 595, "SMLR": 194, "GME": 517, "CANG": 337, "ADE.DE": 11, "0434.HK": 238, | |
| "HOLO": 508, "SQNS": 644, "HIVE": 9, "EXOD": 168, "ALTBG.PA": 295, "3659.T": 14, "FUFU": 325, "BTDR": 324, "SWC.AQ": 440, "FLD": 256, | |
| "CAN": 111, "BITF": 12, "CIFR": 82, "3825.T": 301, "KULR": 341, "NA": 331, "CORZ": 3, "MSW": 356, "SOS": 426, "BTCT.V": 608, | |
| "AKER.OL": 15, "GS9": 491, "CASH3.SA": 395, "MELI": 182, "SRAG.DU": 279, "JAS.BK": 307, "DCC.AX": 24, "ARLP": 425, "377030.KQ": 401, "BTBT": 18, | |
| "NDA.V": 32, "DDC": 500, "NTHOL.IS": 40, "DMGI.V": 23, "NCTY": 442, "VLCN": 679, "PNIX.AQ": 582, "ABT.DU": 21, "LQWD.V": 29, "CS.ST": 288, | |
| "VIRT": 472, "112040.KQ": 403, "RUM": 402, "DEFI.NE": 254, "GNS": 294, "PRE": 573, "3189.T": 445, "BTCB.SE": 636, "LMFA": 91, "BMNR": 550, | |
| "SIX.CN": 597, "BNXAF": 30, "PHX.AD": 449, "HKHC": 480, "042420.KQ": 406, "BTC.BK": 31, "K33.ST": 538, "COIN.AQ": 483, "BIGG.V": 17, "BTM": 372, | |
| "KWM": 643, "BTC.L": 292, "8005.HK": 342, "MATA.V": 357, "VANA.MC": 535, "V3TC.AQ": 586, "SBC": 380, "FRMO": 35, "ATAI": 479, "CBIT.V": 27, | |
| "MLGO": 511, "MOGO": 36, "8267.HK": 239, "WNDR.TO": 242, "SATO.V": 240, "9238.T": 434, "1723.HK": 384, "PXI.CN": 634, "SATS.L": 666, "ALBDM.PA": 580, | |
| "IREN": 12, "WULF": 15, "GREE": 21, "EBON": 14, "DGHI": 25, "SDIG": 17, "MIGI": 16, "SLNH": 24, "ANY": 23, "APLD": 20, | |
| "BTCS": 19, "RVYL": 30, "ICG": 29, "HOOD": 35, "PYPL": 2, "NVDA": 22, "CME": 26, "DEFI": 31, "IBIT": 119, "BTF": 33, | |
| "SQ": 34, "BKKT": 37, "BTCM": 38, "MA": 39, "IBM": 40, "GBTC": 50, "BITO": 41, "BITB": 117, "BTC-USD": 0, "MTPLF": 176 | |
| } | |
| # Diccionario global para almacenar los datos hist贸ricos | |
| def evolucion_correlacion(ticker_company, step, ticker_btc="BTC-USD", window_months=12): | |
| """ | |
| Calcula la evoluci贸n de la correlaci贸n entre el precio de las acciones de una empresa y Bitcoin. | |
| Args: | |
| ticker_company (str): El s铆mbolo de cotizaci贸n de la empresa. | |
| step (int): El n煤mero de d铆as para el desplazamiento de la correlaci贸n. | |
| ticker_btc (str): El s铆mbolo de cotizaci贸n de Bitcoin (por defecto: "BTC-USD"). | |
| window_months (int): El tama帽o de la ventana m贸vil en meses. | |
| outputs: | |
| pandas.Series: Una serie con la evoluci贸n de la correlaci贸n, o None si faltan datos. | |
| """ | |
| end_date = datetime.now() | |
| start_date = end_date - timedelta(days=10*365) | |
| if ticker_company not in all_historical_data: | |
| print(f"Descargando datos para {ticker_company}...") | |
| data = yf.download(ticker_company, start=start_date, end=end_date) | |
| if not data.empty: | |
| all_historical_data[ticker_company] = data | |
| print(f"Datos de {ticker_company} descargados con 茅xito.") | |
| else: | |
| print(f"Error al descargar datos para {ticker_company}.") | |
| return None | |
| if ticker_btc not in all_historical_data: | |
| print(f"Descargando datos para {ticker_btc}...") | |
| data = yf.download(ticker_btc, start=start_date, end=end_date) | |
| if not data.empty: | |
| all_historical_data[ticker_btc] = data | |
| print(f"Datos de {ticker_btc} descargados con 茅xito.") | |
| else: | |
| print(f"Error al descargar datos para {ticker_btc}.") | |
| return None | |
| company_data = all_historical_data.get(ticker_company) | |
| btc_data = all_historical_data.get(ticker_btc) | |
| if company_data.empty or btc_data.empty: | |
| print(f"No podemos calcular la correlaci贸n din谩mica: No hay datos disponibles para {ticker_company} o {ticker_btc}.") | |
| return None | |
| company_prices = company_data['Close'] | |
| btc_prices = btc_data['Close'] | |
| combined_prices = pd.concat([company_prices, btc_prices], axis=1).dropna() | |
| combined_prices.columns = [ticker_company, ticker_btc] | |
| if combined_prices.empty: | |
| print(f"No hay datos hist贸ricos en com煤n entre {ticker_company} y {ticker_btc}.") | |
| return None | |
| company_returns = combined_prices[ticker_company].pct_change().dropna() | |
| btc_returns = combined_prices[ticker_btc].pct_change().dropna() | |
| window_days = window_months * 30 | |
| if step == 0: | |
| dynamic_corr = company_returns.rolling(window=f"{window_days}D").corr(btc_returns).iloc[-1] | |
| return pd.Series([dynamic_corr], index=[end_date]) | |
| else: | |
| dynamic_corr = company_returns.rolling(window=f"{window_days}D").corr(btc_returns).dropna() | |
| return dynamic_corr.iloc[9::step] | |
| def limpiar_texto(texto): | |
| """Elimina caracteres especiales y espacios extra.""" | |
| texto_limpio_parcial = re.sub(r'[^a-zA-Z0-9.,\s]', '', texto) | |
| texto_final = texto_limpio_parcial.strip() | |
| return texto_final | |
| def expand_money(val): | |
| """Convierte strings de dinero (ej. '$1.2B') a valores flotantes.""" | |
| if pd.isna(val): | |
| return np.nan | |
| val = str(val).replace('$', '').replace(',','').upper() | |
| try: | |
| if 'B' in val: | |
| return float(val.replace('B', '')) * 1_000_000_000 | |
| elif 'M' in val: | |
| return float(val.replace('M', '')) * 1_000_000 | |
| elif 'K' in val: | |
| return float(val.replace('K', '')) * 1_000 | |
| else: | |
| return float(val) | |
| except: | |
| return np.nan | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import pandas as pd | |
| def descargar_tabla_web(url, indice_tabla=0): | |
| """ | |
| Descarga una tabla de una URL usando ScraperAPI para evitar bloqueos. | |
| """ | |
| api_key = '7b033896bff116ad0fcc94b29c52c923' # Reemplaza esto con tu clave de ScraperAPI | |
| api_url = f"http://api.scraperapi.com?api_key={api_key}&url={url}" | |
| try: | |
| response = requests.get(api_url) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| tables = soup.find_all('table') | |
| if len(tables) > indice_tabla: | |
| table = tables[indice_tabla] | |
| else: | |
| print(f"No se encontr贸 la tabla con 铆ndice {indice_tabla} en la p谩gina: {url}.") | |
| return None | |
| # El resto del c贸digo para extraer los datos de la tabla sigue igual | |
| headers = [th.text.strip() for th in table.find_all('th')] | |
| data = [] | |
| for row in table.find_all('tr'): | |
| cols = row.find_all('td') | |
| cols = [ele.text.strip() for ele in cols] | |
| if cols: | |
| data.append(cols) | |
| if headers and data and len(headers) == len(data[0]): | |
| df = pd.DataFrame(data, columns=headers) | |
| else: | |
| df = pd.DataFrame(data) | |
| return df | |
| except requests.exceptions.RequestException as e: | |
| print(f"Error al acceder a la URL: {e}") | |
| return None | |
| except Exception as e: | |
| print(f"Ocurri贸 un error inesperado: {e}") | |
| return None | |
| def generar_tickers(): | |
| """ | |
| Genera una lista global de tickers a partir de las tablas de stocks y ETFs. | |
| """ | |
| global tickers | |
| tickers = [] | |
| # URLs de donde obtener los datos | |
| url_stocks = "https://bitcointreasuries.net/" | |
| url_etfs = "https://bitcointreasuries.net/etfs-and-exchanges" | |
| # Descargar tablas web (se asume que estas funciones existen) | |
| df_stocks = descargar_tabla_web(url_stocks, indice_tabla=3) | |
| df_etfs = descargar_tabla_web(url_etfs, indice_tabla=3) | |
| # Procesar Stocks si existen | |
| if df_stocks is not None and not df_stocks.empty: | |
| # Asumiendo que limpiar_texto ya est谩 definida | |
| df_stocks[['Name', 'Ticker']] = df_stocks[2].apply(limpiar_texto).str.rsplit(' ', n=1, expand=True) | |
| tickers.extend(df_stocks['Ticker'].dropna().tolist()) | |
| # Procesar ETFs si existen | |
| if df_etfs is not None and not df_etfs.empty: | |
| df_etfs[['Name', 'Ticker']] = df_etfs[2].apply(limpiar_texto).str.rsplit(' ', n=1, expand=True) | |
| df_etfs['Ticker'].fillna(df_etfs['Name'], inplace=True) | |
| tickers.extend(df_etfs['Ticker'].dropna().tolist()) | |
| generar_tickers() | |
| def extract_file_id(url): | |
| """Extrae el ID del archivo de una URL de Google Drive.""" | |
| match = re.search(r'/d/([a-zA-Z0-9_-]+)', url) | |
| if match: | |
| return match.group(1) | |
| return None | |
| def descargar_resumen_holding_excel(template_url): | |
| """ | |
| Descarga los datos de holding de BTC para stocks y ETFs, | |
| los procesa, calcula correlaciones y exporta a un archivo Excel | |
| usando una plantilla de Google Drive. | |
| """ | |
| try: | |
| # Extraer el ID del archivo de la URL | |
| file_id = extract_file_id(template_url) | |
| if not file_id: | |
| return None, "Error: No se pudo extraer el ID del archivo de la URL de Google Drive." | |
| local_template_path = 'plantilla_temporal.xlsx' | |
| # Descargar la plantilla de Google Drive | |
| try: | |
| gdown.download(id=file_id, output=local_template_path, quiet=False) | |
| except Exception as e: | |
| return None, f"Error al descargar la plantilla desde Google Drive: {e}" | |
| url_stocks = "https://bitcointreasuries.net/" | |
| url_ETFs = "https://bitcointreasuries.net/etfs-and-exchanges" | |
| df_stocks = descargar_tabla_web(url_stocks, indice_tabla=3) | |
| df_etfs = descargar_tabla_web(url_ETFs, indice_tabla=3) | |
| if df_stocks is None and df_etfs is None: | |
| return None, "Error: No se pudieron descargar los datos de holding." | |
| # Procesar Stocks | |
| if df_stocks is not None: | |
| df_descargado_stocks = df_stocks[[2,3,4,5,12]].copy() | |
| df_descargado_stocks.columns = ['Name','Bitcoin', 'BTC in USD', 'Marketcap', '% Total BTC 21M'] | |
| df_descargado_stocks[['Name','Ticker']] = df_descargado_stocks['Name'].apply(limpiar_texto).str.rsplit(' ', n=1, expand=True) | |
| df_descargado_stocks['Bitcoin'] = df_descargado_stocks['Bitcoin'].apply(limpiar_texto) | |
| df_descargado_stocks['Marketcap'] = df_descargado_stocks['Marketcap'].apply(limpiar_texto) | |
| df_descargado_stocks['BTC in USD'] = df_descargado_stocks['BTC in USD'].apply(expand_money) | |
| df_descargado_stocks['Marketcap'] = df_descargado_stocks['Marketcap'].apply(expand_money) | |
| df_descargado_stocks['Ratio Holding/Mcap'] = df_descargado_stocks['BTC in USD'] / df_descargado_stocks['Marketcap'] | |
| corrls = [] | |
| for stock in df_descargado_stocks['Ticker']: | |
| try: | |
| corr_value = evolucion_correlacion(stock, step=0, window_months=12).iloc[0] | |
| corrls.append(corr_value) | |
| except Exception as e: | |
| print(f"Error al calcular correlaci贸n para {stock}: {e}") | |
| corrls.append(np.nan) | |
| df_descargado_stocks['Correlaci贸n con BTC (12 meses)'] = pd.Series(corrls) | |
| df_descargado_stocks.set_index('Ticker', inplace=True) | |
| else: | |
| df_descargado_stocks = pd.DataFrame() | |
| # Procesar ETFs | |
| if df_etfs is not None: | |
| global df_descargado_ETFs | |
| df_descargado_ETFs = df_etfs[[2,3,4,5]].copy() | |
| df_descargado_ETFs.columns = ['Name','Bitcoin', 'BTC in USD','% Total BTC 21M'] | |
| df_descargado_ETFs[['Name','Ticker']] = df_descargado_ETFs['Name'].apply(limpiar_texto).str.rsplit(' ', n=1, expand=True) | |
| df_descargado_ETFs['Ticker'].fillna(df_descargado_ETFs['Name'], inplace=True) | |
| df_descargado_ETFs['BTC in USD'] = df_descargado_ETFs['BTC in USD'].apply(expand_money) | |
| df_descargado_ETFs['Bitcoin'] = df_descargado_ETFs['Bitcoin'].apply(limpiar_texto).apply(expand_money) | |
| df_descargado_ETFs.set_index('Ticker', inplace=True) | |
| else: | |
| df_descargado_ETFs = pd.DataFrame() | |
| # A帽adir la columna de 'Options' como solicitaste | |
| global tickers | |
| tickers = [] | |
| if not df_descargado_stocks.empty: | |
| tickers.extend(df_descargado_stocks.index.tolist()) | |
| if not df_descargado_ETFs.empty: | |
| tickers.extend(df_descargado_ETFs.index.tolist()) | |
| options_bool = {} | |
| for ticker in tickers: | |
| if ticker is not None: | |
| try: | |
| options_bool[ticker] = False if not yf.Ticker(ticker).options else True | |
| except: | |
| options_bool[ticker] = False | |
| options_series = pd.Series(options_bool) | |
| if not df_descargado_stocks.empty: | |
| df_descargado_stocks['Options'] = options_series | |
| if not df_descargado_ETFs.empty: | |
| df_descargado_ETFs['Options'] = options_series | |
| # Exportaci贸n a Excel | |
| if not df_descargado_stocks.empty or not df_descargado_ETFs.empty: | |
| nuevo_archivo_path = 'resumen_datos_holding.xlsx' | |
| # Copiar la plantilla descargada antes de escribir | |
| try: | |
| shutil.copyfile(local_template_path, nuevo_archivo_path) | |
| except FileNotFoundError: | |
| return None, f"Error: No se encontr贸 la plantilla en la ruta: {local_template_path}" | |
| # Escribir en el archivo copiado | |
| with pd.ExcelWriter(nuevo_archivo_path, engine='openpyxl', mode='a', if_sheet_exists='replace') as writer: | |
| if not df_descargado_stocks.empty: | |
| df_descargado_stocks.to_excel(writer, sheet_name='Stocks', index=True) | |
| if not df_descargado_ETFs.empty: | |
| df_descargado_ETFs.to_excel(writer, sheet_name='ETFs', index=True) | |
| # Eliminar la plantilla temporal descargada para limpiar el entorno | |
| os.remove(local_template_path) | |
| return nuevo_archivo_path, "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}" | |
| # Funciones para Gradio | |
| def plot_evolucion_correlacion_gradio(ticker_company, step, window_months): | |
| """ | |
| Genera el gr谩fico de la evoluci贸n de la correlaci贸n. | |
| """ | |
| serie = evolucion_correlacion(ticker_company, step, window_months=12) | |
| if serie is None or serie.empty: | |
| return None, f"No hay datos de correlaci贸n disponibles para {ticker_company}." | |
| # --- Create the Plotly graph --- | |
| fig = go.Figure() | |
| # Add the correlation series | |
| fig.add_trace(go.Scatter( | |
| x=serie.index, | |
| y=serie.values, | |
| mode='lines', | |
| name='Correlaci贸n', | |
| line=dict(color='#2263eb', width=2), # electric blue color for the line | |
| fill='tozeroy', # Fill the area down to Y=0 axis | |
| fillcolor='rgba(34,99,235,0.1)', # Very faint elctric blue shadow (10% opacity) | |
| hovertemplate='Fecha: %{x|%Y-%m-%d}<br>Correlaci贸n: %{y:.4f}<extra></extra>' | |
| )) | |
| # --- Configure axes and range selector --- | |
| fig.update_layout( | |
| title_text=f'<b>Evoluci贸n de la correlaci贸n entre {ticker_company} y BTC-USD<b>', | |
| title_x=0, # Align title to the left | |
| height=500, # Graph height | |
| template="plotly_white", # Graph theme (clean and modern) | |
| margin=dict(l=20, r=20, t=60, b=20), # Graph margins | |
| showlegend=False, # No legend needed if only one main series | |
| xaxis=go.layout.XAxis( | |
| rangeslider=dict( | |
| visible=True, | |
| thickness=0.08, # Rangeslider thickness | |
| bgcolor="rgba(50, 0, 128, 0.1)", # Very transparent purple for rangeslider | |
| bordercolor="rgba(50, 0, 128, 0.2)", # Slightly more visible border | |
| borderwidth=1, | |
| range=[serie.index.min(), serie.index.max()] # Initial slider range | |
| ), | |
| rangeselector=dict( | |
| buttons=list([ | |
| dict(count=1, label="1m", step="month", stepmode="backward"), | |
| dict(count=3, label="3m", step="month", stepmode="backward"), | |
| dict(count=6, label="6m", step="month", stepmode="backward"), | |
| dict(step="year", count=1, label="YTD", stepmode="todate"), # YTD | |
| dict(count=1, label="1y", step="year", stepmode="backward"), | |
| dict(step="all", label="All") | |
| ]), | |
| bgcolor="rgba(247,247,247,255)", # Transparent background for buttons | |
| bordercolor="rgba(0,0,0,0)", # Transparent border | |
| borderwidth=0, | |
| activecolor="rgba(230,233,255,255)", # Active button color (slightly darker purple) | |
| font=dict(color="#000000", size=10), # Button font style | |
| x=0.9, y=1.1, xanchor='right', yanchor='top' # Button position | |
| ), | |
| type="date", | |
| domain=[0, 1], # Occupy full graph width | |
| rangeslider_yaxis_rangemode="auto", # Rangeslider Y-axis range adjusts automatically | |
| showgrid=False, | |
| gridcolor='#e0e0e0', | |
| zeroline=False | |
| ), | |
| yaxis=go.layout.YAxis( | |
| title_text='Correlaci贸n', | |
| side='left', | |
| showgrid=True, | |
| gridcolor='#e0e0e0', | |
| zeroline=False, | |
| tickformat=".2f", # 2 decimal places format | |
| range=[-1.0, 1.0] # Fixed range for correlation | |
| ), | |
| hovermode="x unified", # Unify hover to show data for the series | |
| paper_bgcolor='rgba(255,255,255,1)', # Transparent background for notebook integration | |
| plot_bgcolor='rgba(255,255,255,1)' | |
| ) | |
| # --- Add annotation for max value (similar to Matplotlib) --- | |
| max_value = serie.max() | |
| max_index = serie.idxmax() | |
| fig.add_annotation( | |
| x=max_index, | |
| y=max_value, | |
| text=f'Corr_max: {max_value:.4f}<br>Fecha: {max_index.date()}', | |
| showarrow=True, | |
| arrowhead=2, | |
| ax=0, | |
| ay=-40, # Adjust vertical position of the annotation | |
| bgcolor="rgba(255, 255, 255, 0.8)", # Semi-transparent white background | |
| bordercolor="#c7c7c7", | |
| borderwidth=1, | |
| borderpad=4, | |
| font=dict(size=10, color="#333"), | |
| # You can adjust text position with xanchor/yanchor if needed | |
| ) | |
| return fig, "Gr谩fico de correlaci贸n generado." | |
| """ | |
| if serie is None or serie.empty: | |
| return plt.figure(), f"No hay datos de correlaci贸n disponibles para {ticker_company}." | |
| max_value = serie.max() | |
| min_value = serie.min() | |
| max_index = serie.idxmax() | |
| plt.figure(figsize=(10, 6)) | |
| plt.plot(serie) | |
| plt.xlabel('Fecha') | |
| plt.ylabel('Correlaci贸n') | |
| plt.title(f'Evoluci贸n de la correlaci贸n entre {ticker_company} y BTC-USD') | |
| plt.plot(max_index, max_value, 'ro') | |
| plt.annotate(f' Corr_max: {max_value:.4f} \n Fecha: {max_index.date()}', (max_index, max_value), xytext=(max_index, max_value - (max_value - min_value) * 0.15)) | |
| lower_margin = min_value - 0.1 * abs(min_value) | |
| upper_margin = max_value + 0.05 * abs(max_value) | |
| plt.ylim(lower_margin, upper_margin) | |
| plt.tight_layout() | |
| return plt.gcf(), "Gr谩fico de correlaci贸n generado." | |
| """ | |
| def exportar_correlacion(ticker_company, step, window_months): | |
| """ | |
| Exporta la serie de correlaci贸n a un archivo Excel. | |
| """ | |
| try: | |
| serie = evolucion_correlacion(ticker_company, step, window_months=window_months) | |
| if serie is not None and not serie.empty: | |
| nombre_archivo = f'{ticker_company}_evolucion_correlacion.xlsx' | |
| serie.to_excel(nombre_archivo) | |
| 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 get_iframe_stock_vs_btc(ticker): | |
| """ | |
| Genera el c贸digo HTML para el iframe de Stock vs Bitcoin. | |
| """ | |
| try: | |
| entity_id = tickers_to_ids[ticker] | |
| iframe_code = f""" | |
| <iframe src="https://bitcointreasuries.net/embed?component=StockVsBitcoinChart&entityId={entity_id}" | |
| title="Bitcoin Treasuries" credentialless style="width: 100%; height: 660px; border: none;"></iframe> | |
| """ | |
| return iframe_code | |
| except KeyError: | |
| return f"No hay datos de holding de Bitcoin para {ticker}." | |
| def get_iframe_holdings(ticker): | |
| """ | |
| Genera el c贸digo HTML para el iframe de Bitcoin Holdings. | |
| """ | |
| try: | |
| entity_id = tickers_to_ids[ticker] | |
| iframe_code = f""" | |
| <iframe src="https://bitcointreasuries.net/embed?component=BitcoinHoldingsChart&entityId={entity_id}" | |
| title="Bitcoin Holdings Chart" credentialless style="width: 100%; height: 660px; border: none;"></iframe> | |
| """ | |
| return iframe_code | |
| except KeyError: | |
| return f"No hay datos de holding de Bitcoin para {ticker}." | |
| ### CONFIGURACION DE GRADIO: | |
| with gr.Blocks(title="An谩lisis de Correlaci贸n") as demo: | |
| gr.Image("https://cdn.prod.website-files.com/67174dcb1d43b06a0eae317e/672bbbc7a2b88045e5661994_logo-afi.svg", show_label=False) | |
| gr.Markdown("# Analizador de Correlaci贸n de Bitcoin") | |
| gr.Markdown("Explora la correlaci贸n de diferentes activos con Bitcoin y sus holdings.") | |
| with gr.Row(): | |
| input_ticker = gr.Dropdown( | |
| label="Ticker de la Empresa", | |
| choices= tickers, ### hacer que la lista sea dinamica, luego miraremos el tema de los ids | |
| value="MSTR", | |
| allow_custom_value=True | |
| ) | |
| with gr.Tab("Evoluci贸n de Correlaci贸n"): | |
| gr.Markdown("### Evoluci贸n de la correlaci贸n") | |
| with gr.Row(): | |
| input_step = gr.Slider(minimum=1, maximum=30, value=1, step=1, label="Indica cada cu谩ntos d铆as se calcula la correlaci贸n") | |
| input_window = gr.Slider(minimum=1, maximum=60, value=12, step=1, label="Ventana rolling (meses)") | |
| btn_plot = gr.Button("Mostrar Gr谩fico") | |
| output_plot = gr.Plot(label="Gr谩fico de Evoluci贸n") | |
| btn_excel = gr.Button("Descargar en Excel") | |
| output_file = gr.File(label="Archivo Excel") | |
| output_msg = gr.Label() | |
| btn_plot.click( | |
| fn=plot_evolucion_correlacion_gradio, | |
| inputs=[input_ticker, input_step, input_window], | |
| outputs=[output_plot, output_msg] | |
| ) | |
| btn_excel.click( | |
| fn=exportar_correlacion, | |
| inputs=[input_ticker, input_step, input_window], | |
| outputs=[output_file, output_msg] | |
| ) | |
| with gr.Tab("Stock vs BTC"): | |
| gr.Markdown("### Gr谩fico de Stock vs Bitcoin") | |
| btn_stock_btc = gr.Button("Cargar Gr谩fico") | |
| gr.Markdown("**NAV Multiplier:** \n\n Muestra la relaci贸n entre el precio de la acci贸n de la empresa y el valor de sus activos.") | |
| output_iframe_stock = gr.HTML(label="Stock vs Bitcoin Chart") | |
| btn_stock_btc.click( | |
| fn=get_iframe_stock_vs_btc, | |
| inputs=[input_ticker], | |
| outputs=[output_iframe_stock] | |
| ) | |
| with gr.Tab("Holding de Bitcoin"): | |
| gr.Markdown("### Gr谩fico de Holding de Bitcoin") | |
| btn_holdings = gr.Button("Cargar Gr谩fico") | |
| output_iframe_holdings = gr.HTML(label="Bitcoin Holdings Chart") | |
| btn_holdings.click( | |
| fn=get_iframe_holdings, | |
| inputs=[input_ticker], | |
| outputs=[output_iframe_holdings] | |
| ) | |
| with gr.Tab("Exportar Resumen Holding"): | |
| gr.Markdown("### Descargar resumen de holdings a Excel") | |
| gr.Markdown("Esto descargar谩 los datos de holding de BTC de la web, los procesar谩 y crear谩 un archivo Excel a partir de una plantilla.") | |
| # Agregado el input para la URL de la plantilla de Google Drive | |
| input_template_url = gr.Textbox( | |
| label="URL de la plantilla de Excel (Google Drive)", | |
| value="https://docs.google.com/spreadsheets/d/1Ad3bbYQAAZO6ljkaCGTGSw5aG_FQF7Lg/edit?usp=sharing&ouid=109222615757657219494&rtpof=true&sd=true", | |
| placeholder="Ej: https://docs.google.com/spreadsheets/d/ID_DEL_ARCHIVO/..." | |
| ) | |
| btn_descargar_resumen = gr.Button("Descargar Resumen a Excel") | |
| output_resumen_file = gr.File(label="Archivo de Resumen de Holdings") | |
| output_resumen_msg = gr.Label() | |
| btn_descargar_resumen.click( | |
| fn=descargar_resumen_holding_excel, | |
| inputs=[input_template_url], # Ahora pasamos la URL como input | |
| outputs=[output_resumen_file, output_resumen_msg] | |
| ) | |
| #Inicia la aplicaci贸n | |
| demo.launch(share=True) |