import yfinance as yf from datetime import datetime import pandas as pd import gradio as gr # FUNCTION TO GET STOCK DATA def get_stock_data(ticker): # Max Rows and Columns pd.set_option('display.max_columns', 500) pd.set_option('display.max_rows', None) # Two Decimals pd.options.display.float_format = '{:.2f}'.format # The stock symbol symbol = ticker ticker = yf.Ticker(symbol) company_name = ticker.info.get("longName", "N/A") # Get historical share prices price_history = ticker.history(period='5y') # Extract the closing prices at the end of each fiscal year # We will reindex to have end-of-year dates that match the years of the income statements year_end_prices = price_history.resample('A').last()['Close'] year_end_prices.index = year_end_prices.index.year # Get the number of shares from the info or financials shares_outstanding = ticker.info.get('sharesOutstanding') # Get the annual income statement data income_statement = ticker.financials # Transpose the income statement to have years as rows income_statement = income_statement.T # Extract net income and calculate EPS income_statement['EPS'] = income_statement['Net Income'] / shares_outstanding # Convert the 'Date' index to a year income_statement.index = income_statement.index.year # Combine EPS and closing prices into one DataFrame pe_ratios_df = pd.DataFrame({ 'Year': income_statement.index, 'EPS': income_statement['EPS'], 'Revenue': income_statement['Total Revenue'], 'Closing Price': year_end_prices.reindex(income_statement.index).values }) # Calculate the P/E ratio pe_ratios_df['P/E Ratio'] = pe_ratios_df['Closing Price'] / pe_ratios_df['EPS'] # Calculate Market Capitalization for each year (Closing Price * Shares Outstanding) pe_ratios_df['Market Cap'] = pe_ratios_df['Closing Price'] * shares_outstanding # Calculate the P/S ratio pe_ratios_df['P/S Ratio'] = pe_ratios_df['Market Cap'] / pe_ratios_df['Revenue'] # Create DataFrame with last 10 years current_year = datetime.now().year # Create a list of the last 10 years years = list(range(current_year - 9, current_year + 1)) # Create a DataFrame df_years = pd.DataFrame({'Year': years}) # Get the historical dividend data dividend_data = ticker.dividends # Convert the Series to a DataFrame dividend_df = dividend_data.reset_index() # Rename the columns for clarity dividend_df.columns = ['Date', 'Dividend'] # Extract the year from the Date column dividend_df['Year'] = dividend_df['Date'].dt.year # Group by Year and get the last dividend of each year dividend_df = dividend_df.groupby('Year').last().reset_index() # Merge DataFrames dividend_df = pd.merge(df_years, dividend_df, on='Year', how='left') # Replace NaN with last years value dividend_df['Dividend'] = dividend_df['Dividend'].ffill() # Sort the DataFrame by Year dividend_df = dividend_df.sort_values(by='Year') # Calculate the 3-year percentage change dividend_df['Dividend Growth (3y)'] = dividend_df['Dividend'].pct_change(periods=3) * 100 # Calculate the 5-year percentage change dividend_df['Dividend Growth (5y)'] = dividend_df['Dividend'].pct_change(periods=5) * 100 # Calculate the 10-year percentage change dividend_df['Dividend Growth (10y)'] = dividend_df['Dividend'].pct_change(periods=10) * 100 # Drop Columns dividend_df = dividend_df.drop(columns=['Dividend']) print(dividend_df) # Get the historical stock price data for the last 10 years price_history = ticker.history(period='10y') # Initialize a list to accumulate the annual data value_data = [] # Start with an initial investment value of 1 share initial_value = price_history['Close'].iloc[0] cumulative_value = initial_value # Track the last year processed to ensure we only capture the final value for each year last_year = price_history.index[0].year # Iterate over each date in the price history to calculate the value including dividends for i in range(len(price_history)): current_date = price_history.index[i] current_price = price_history['Close'].iloc[i] current_year = current_date.year # Check if any dividends were paid out on the current date if current_date in dividend_df['Date'].values: dividend = dividend_df[dividend_df['Date'] == current_date]['Dividend'].values[0] # Calculate the value increase due to dividends cumulative_value += (dividend / current_price) * cumulative_value # Update the cumulative value with the price change if i < len(price_history) - 1: next_price = price_history['Close'].iloc[i + 1] cumulative_value *= (next_price / current_price) # At the end of each year, record the value including dividends if current_year != last_year: # Append the cumulative value at the end of the previous year value_data.append({'Year': last_year, 'Value Including Dividends': cumulative_value}) last_year = current_year # Append the final value at the end of the last year in the dataset value_data.append({'Year': last_year, 'Value Including Dividends': cumulative_value}) # Convert the accumulated list to a DataFrame value_including_dividends_df = pd.DataFrame(value_data) # Calculate the percentage increase in value including dividends value_including_dividends_df['Value Increase'] = value_including_dividends_df['Value Including Dividends'].pct_change() * 100 # Get the historical dividend data dividend_data = ticker.dividends # Convert the Series to a DataFrame dividend_df2 = dividend_data.reset_index() # Rename the columns for clarity dividend_df2.columns = ['Date', 'Dividend'] # Extract the year from the Date column dividend_df2['Year'] = dividend_df2['Date'].dt.year # Aggregate the annual dividends by summing them up annual_dividends = dividend_df2.groupby('Year')['Dividend'].sum().reset_index() # Calculate the year-over-year dividend increase annual_dividends['Dividend Increase'] = annual_dividends['Dividend'].diff() > 0 # Calculate the cumulative number of increases annual_dividends['No of Increases'] = annual_dividends['Dividend Increase'].cumsum() # Drop the 'Dividend Increase' column if not needed in the final output annual_dividends = annual_dividends.drop(columns=['Dividend Increase']) # Get the annual income statement data to find EPS income_statement = ticker.financials.T # Extract the EPS (Earnings Per Share) annual_eps = (income_statement['Net Income'] / ticker.info['sharesOutstanding']).reset_index() annual_eps.columns = ['Year', 'EPS'] # Convert the index to years for the EPS DataFrame annual_eps['Year'] = annual_eps['Year'].dt.year # Align the DataFrames on the 'Year' column aligned_dividends_eps = pd.merge(annual_dividends, annual_eps, on='Year', how='outer') # Calculate the Payout Ratio aligned_dividends_eps['Payout Ratio (%)'] = (aligned_dividends_eps['Dividend'] / aligned_dividends_eps['EPS']) * 100 aligned_dividends_eps.sort_values('Year', axis=0, ascending=True, inplace=True) # Get the income statement data income_statement = ticker.financials # Transpose the data to make it easier to read income_statement = income_statement.T # Rename the columns for clarity income_statement = income_statement.rename(columns={'Total Revenue': 'Revenue'}) income_statement = income_statement.rename(columns={'Gross Profit': 'Earnings'}) # Convert Index to Year and rename it to Year and sort by it income_statement['Year'] = income_statement.index.year income_statement = income_statement.sort_values(by='Year') # Calculate Growth Columns income_statement['Revenue Growth'] = income_statement['Revenue'].pct_change() * 100 income_statement['EBITDA Growth'] = income_statement['EBITDA'].pct_change() * 100 # Calculate Margin Columns income_statement['EBITDA Margin'] = (income_statement['EBITDA']/income_statement['Revenue']).pct_change() * 100 # Calculate Gross Profit and Gross Profit Margin and Gross Profit Growth income_statement['GP'] = income_statement['Revenue'] - income_statement['Cost Of Revenue'] income_statement['GP Margin'] = (income_statement['GP'] / income_statement['Revenue']) * 100 # Calculate Gross Profit Growth income_statement['GP Growth'] = income_statement['GP'].pct_change() * 100 # Format EBITDA income_statement['EBITDA MEUR'] = income_statement['EBITDA'] / 1000000 income_df = income_statement[['Year','EBITDA MEUR', 'Revenue Growth', 'GP Margin', 'GP Growth', 'EBITDA Margin', 'EBITDA Growth']] # Get the cashflow data cashflow_data = ticker.cashflow # Transpose the data to have years as rows cashflow_statement = cashflow_data.T # Get the number of shares outstanding from the info shares_outstanding = ticker.info.get('sharesOutstanding') # Extract Cash Flow from Operations and CapEx cashflow_operations = cashflow_statement['Operating Cash Flow'] capex = cashflow_statement['Capital Expenditure'] cashflow = cashflow_statement['Free Cash Flow'] # Calculate Cash Flow per Share cashflow_per_share = cashflow_operations / shares_outstanding # Calculate Free Cash Flow (FCF) cashflow = cashflow_operations + capex # CapEx is typically a negative number in the cash flow statement # Convert the 'Date' index to a year cashflow.index = cashflow.index.year # Create a DataFrame for display cashflow_df = pd.DataFrame({ 'Year': cashflow.index, 'Cashflow Operations': cashflow_operations.values, 'Cashflow per Share': cashflow_per_share, #'Capital Expenditures': capex.values, 'Free Cashflow': cashflow.values }) # Get the annual balance sheet data balance_sheet = ticker.balance_sheet # Transpose the data to have years as rows balance_sheet = balance_sheet.T # Extract Total Stockholder Equity total_equity = balance_sheet['Stockholders Equity'] # Get the number of shares outstanding from the info shares_outstanding = ticker.info.get('sharesOutstanding') # Calculate Book Value per Share book_value_per_share = total_equity / shares_outstanding # Extract Total Debt and Cash Equivalents total_debt = balance_sheet['Total Debt'] cash_and_equivalents = balance_sheet['Cash And Cash Equivalents'] # Calculate Net Financial Liabilities net_financial_liabilities = total_debt - cash_and_equivalents # Convert the index to years net_financial_liabilities.index = net_financial_liabilities.index.year # Create a DataFrame for display net_financial_liabilities_df = pd.DataFrame({ 'Year': net_financial_liabilities.index, 'Bookvalue per Share': book_value_per_share, 'Total Debt': total_debt.values, 'Cash': cash_and_equivalents.values, 'Net Financial Liabilities': net_financial_liabilities.values }) # Merge DataFrames df = pd.merge(pe_ratios_df, annual_dividends, on='Year', how='left') df = pd.merge(df, value_including_dividends_df, on='Year', how='inner') df = pd.merge(df, income_df, on='Year', how='inner') df = pd.merge(df, dividend_df, on='Year', how='left') df = pd.merge(df, cashflow_df, on='Year', how='inner') df = pd.merge(df, net_financial_liabilities_df, on='Year', how='inner') return company_name, df # CREATE GRADIO INTERFACE with gr.Blocks(title='Stock Data Analysis') as demo: gr.Markdown("# Stock Data Viewer\nEnter a stock ticker symbol to view the historical data.") with gr.Row(): ticker_input = gr.Textbox(label="Enter Ticker Symbol") with gr.Row(): submit_btn = gr.Button("Submit") ticker_headline = gr.Markdown("") with gr.Row(): data_output = gr.Dataframe() def show_dataframe(ticker): company_name, df = get_stock_data(ticker) headline = f"### Data for {company_name} ({ticker})" return headline, df submit_btn.click(show_dataframe, inputs=ticker_input, outputs=[ticker_headline, data_output]) demo.launch(share=True)