Emmatassone / GEN-Bots

1 stars 0 forks source link

Ejemplo de análisis y visualización de datos en DFs con columnas con nombres comunes #19

Closed chao5monkey closed 11 months ago

chao5monkey commented 11 months ago

Este PR muestra cómo se pueden implementar algoritmos de análisis y visualización de datos bajo el supuesto de que los datos se comunican mediante dataframes con nombres de columnas estandarizados. Estandarizar el formato de los dataframes permite homogeneizar el formato de los datos a través de distintas fuentes. Si suponemos que existen fuentes de datos X e Y, tanto el proceso que toma datos de X, como el proceso que toma datos de Y, pueden producir dataframes con formatos similares, independientemente de los respectivos formatos de X e Y. El usuario del dataframe no necesita saber de dónde provienen los datos ni necesita adaptarlos, lo que simplifica los algoritmos de análisis y desacopla al procedimiento de análisis del procedimiento de producción de los datos.

En principio un productor genera datos en un formato común independiente de la fuente. Como ejemplo se implementó un wrapper sobre yfinance que traduce los conceptos de Yahoo Finance al lenguaje interno:

BALANCE_SHEET_MAPPING = {
    concept.TOTAL_ASSETS: 'Total Assets',
    concept.STOCKHOLDER_EQUITY: 'Common Stock Equity',
    concept.DEBT_AND_LEASE_CURRENT: 'Current Debt And Capital Lease Obligation',
    concept.DEBT_AND_LEASE_NON_CURRENT: 'Long Term Debt And Capital Lease Obligation',
}

def fetch_balance_sheet(ticker_symbol: str, frequency: Frequency = FREQ_YEARLY) -> pd.DataFrame:
    # Initialize client.
    source = yfinance.Ticker(ticker_symbol)
    # Get balance sheet.
    balance_sheet = source.get_balance_sheet(pretty=True, freq=frequency)
    # Translate Yahoo Finance representation into internal common representation.
    df = pd.DataFrame({key: balance_sheet.loc[value] for key, value in BALANCE_SHEET_MAPPING.items()})
    # Add ticker symbol to all rows.
    df.insert(0, concept.TICKER_SYMBOL, ticker_symbol)
    # Set time.
    df.reset_index(inplace=True)
    df.rename(columns={'index': concept.PERIOD_START}, inplace=True)
    df.sort_values(by=concept.PERIOD_START, ascending=True, inplace=True)
    #
    return df

El siguiente código genera una visualización del balance entre activos y patrimonio neto en función del tiempo:

def assets_to_equity(
        data: pd.DataFrame,
        ticker_symbol: concept.Key,
        datetime_format: str = '%b %Y',
) -> go.Figure:
    # Filter for the rows for the specific symbol.
    company_rows = data[data[concept.TICKER_SYMBOL] == ticker_symbol]
    # Extract the data that we need.
    t = company_rows[concept.PERIOD_START].dt.strftime(datetime_format)
    a = company_rows[concept.TOTAL_ASSETS]
    e = company_rows[concept.STOCKHOLDER_EQUITY]
    # Generate bar graph.
    fig = go.Figure(data=[
        go.Bar(x=t, y=a, name='Assets', hoverinfo='name+y'),
        go.Bar(x=t, y=e, name='Equity', hoverinfo='name+y'),
    ])
    fig.update_xaxes(type='category')
    fig.update_layout(
        title='{}: Assets to Equity'.format(ticker_symbol),
        xaxis_title='Period Start',
        yaxis_title='Balance',
        barmode='group',
    )
    return fig

El algoritmo no hace supuestos sobre el origen de los datos, por lo que es posible usar el mismo algoritmo con datos provenientes de distintas fuentes, o combinar datos de distintas fuentes para producir el dataframe.

Un ejemplo de código que hace uso de estos componentes es el siguiente:

import ge.finance.datasource.yfinance as yf
balance_sheet = yf.fetch_balance_sheet(ticker_symbol='ALUA.BA')

import ge.finance.visualization.portfolio as v_portfolio
import ge.finance.concept as concept
v_portfolio.assets_to_equity(balance_sheet, ticker_symbol='ALUA.BA', timestamp=concept.PERIOD_END).show()